make_shared 用 shared_ptr 包装动态数组
Wrap dynamic array with shared_ptr by make_shared
我想将一些字节写入数组。为了使用现代 C++,我决定使用智能指针。
#include <memory>
#include <cstdint>
using namespace std;
void writeUint32_t(uint32_t value, unsigned char* p){
*p = static_cast<unsigned char>((value >> 24) & 0xFF);
*(++p) = static_cast<unsigned char>((value >> 16) & 0xFF);
*(++p) = static_cast<unsigned char>((value >> 8) & 0xFF);
*(++p) = static_cast<unsigned char>((value ) & 0xFF);
}
int main(){
auto buf = make_shared<unsigned char[]>(512);
uint32_t data = 1234;
writeUint32_t(data, buf.get() + 8);
}
但是,我收到以下编译错误:
u.cpp:15:37: error: invalid use of array with unspecified bounds
writeUint32_t(data, buf.get() + 8);
^
u.cpp:15:38: error: cannot convert ‘unsigned char (*)[]’ to ‘unsigned char*’ for argument ‘2’ to ‘void writeUint32_t(uint32_t, unsigned char*)’
writeUint32_t(data, buf.get() + 8);
我正在使用 g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
有没有办法在这种情况下使用智能指针?
我建议您使用 std::vector<unsigned char> vec(512);
,包装连续的动态数组正是它的用途。获取原始缓冲区指针就像 vec.data()
;
一样简单
如果向量需要共享,那么你仍然可以使用智能指针
auto p_vec = make_shared<vector<unsigned char>>(512);
由于使用向量,您将获得引用计数的好处,几乎没有开销,并且您将获得整个向量 API。
不要将 std::make_shared
与原始数组一起使用,它不会像您预期的那样构造一个数组,而是会尝试创建一个指向您指定类型的指针,即 unsigned char[]
。这就是为什么在使用 get()
时会得到 unsigned char (*)[]
,如错误消息所述。
和std::shared_ptr
会默认删除delete
的指针,而不是delete[]
,应该用数组。您需要为它指定一个自定义的删除器,但是std::make_shared
不允许您指定它。
您可以 (1) 直接初始化 std::shared_ptr
并指定删除器,例如
std::shared_ptr<unsigned char> buf(new unsigned char[512], [](unsigned char* p)
{
delete[] p;
});
(2) 改用std::unique_ptr
,为数组提供指定版本,包括释放时调用delete[]
,提供operator[]
(std::shared_ptr
会支持从C++17).
auto buf = std::make_unique<unsigned char[]>(512);
(3) 考虑std::vector<unsigned char>
和std::array<unsigned char>
.
如果您真的想为此使用带有数组的 shared_ptr
(而不是 StoryTeller 建议的向量),您的类型应该是 unsigned char
而不是 unsigned char[]
。为了确保数组被正确删除,您需要指定一个数组删除器以传递给 shared_ptr
构造函数(因此您不能使用 make_shared
因为这不允许您指定删除器) :
auto buf = std::shared_ptr<unsigned char>(new unsigned char[512], std::default_delete<unsigned char[]>());
您不能使用:
std::make_shared<unsigned char[]>(512);
那是因为 Type[]
没有 模板专业化 。
那是因为实际上 std::shared_ptr<T>
还 不支持 operator[]
。它将在新标准中 C++17:
operator[] (C++17)
可以使用 STL 容器 或 IMO 更好的解决方案:std::unique_ptr
.
的确,std::unique_ptr
支持operator[]
。
自 C++14 起,您可以:
auto buffer = std::make_unique<unsigned char[]>(512);
buffer[index];
它是异常安全的,几乎是0开销,并且它可以用作数组缓冲区。
此外,缓冲区的释放由 delete[]
运算符的正确调用正确处理。
我想将一些字节写入数组。为了使用现代 C++,我决定使用智能指针。
#include <memory>
#include <cstdint>
using namespace std;
void writeUint32_t(uint32_t value, unsigned char* p){
*p = static_cast<unsigned char>((value >> 24) & 0xFF);
*(++p) = static_cast<unsigned char>((value >> 16) & 0xFF);
*(++p) = static_cast<unsigned char>((value >> 8) & 0xFF);
*(++p) = static_cast<unsigned char>((value ) & 0xFF);
}
int main(){
auto buf = make_shared<unsigned char[]>(512);
uint32_t data = 1234;
writeUint32_t(data, buf.get() + 8);
}
但是,我收到以下编译错误:
u.cpp:15:37: error: invalid use of array with unspecified bounds
writeUint32_t(data, buf.get() + 8);
^
u.cpp:15:38: error: cannot convert ‘unsigned char (*)[]’ to ‘unsigned char*’ for argument ‘2’ to ‘void writeUint32_t(uint32_t, unsigned char*)’
writeUint32_t(data, buf.get() + 8);
我正在使用 g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
有没有办法在这种情况下使用智能指针?
我建议您使用 std::vector<unsigned char> vec(512);
,包装连续的动态数组正是它的用途。获取原始缓冲区指针就像 vec.data()
;
如果向量需要共享,那么你仍然可以使用智能指针
auto p_vec = make_shared<vector<unsigned char>>(512);
由于使用向量,您将获得引用计数的好处,几乎没有开销,并且您将获得整个向量 API。
不要将 std::make_shared
与原始数组一起使用,它不会像您预期的那样构造一个数组,而是会尝试创建一个指向您指定类型的指针,即 unsigned char[]
。这就是为什么在使用 get()
时会得到 unsigned char (*)[]
,如错误消息所述。
和std::shared_ptr
会默认删除delete
的指针,而不是delete[]
,应该用数组。您需要为它指定一个自定义的删除器,但是std::make_shared
不允许您指定它。
您可以 (1) 直接初始化 std::shared_ptr
并指定删除器,例如
std::shared_ptr<unsigned char> buf(new unsigned char[512], [](unsigned char* p)
{
delete[] p;
});
(2) 改用std::unique_ptr
,为数组提供指定版本,包括释放时调用delete[]
,提供operator[]
(std::shared_ptr
会支持从C++17).
auto buf = std::make_unique<unsigned char[]>(512);
(3) 考虑std::vector<unsigned char>
和std::array<unsigned char>
.
如果您真的想为此使用带有数组的 shared_ptr
(而不是 StoryTeller 建议的向量),您的类型应该是 unsigned char
而不是 unsigned char[]
。为了确保数组被正确删除,您需要指定一个数组删除器以传递给 shared_ptr
构造函数(因此您不能使用 make_shared
因为这不允许您指定删除器) :
auto buf = std::shared_ptr<unsigned char>(new unsigned char[512], std::default_delete<unsigned char[]>());
您不能使用:
std::make_shared<unsigned char[]>(512);
那是因为 Type[]
没有 模板专业化 。
那是因为实际上 std::shared_ptr<T>
还 不支持 operator[]
。它将在新标准中 C++17:
operator[] (C++17)
可以使用 STL 容器 或 IMO 更好的解决方案:std::unique_ptr
.
的确,std::unique_ptr
支持operator[]
。
自 C++14 起,您可以:
auto buffer = std::make_unique<unsigned char[]>(512);
buffer[index];
它是异常安全的,几乎是0开销,并且它可以用作数组缓冲区。
此外,缓冲区的释放由 delete[]
运算符的正确调用正确处理。