使用make_shared通过shared_ptr包装动态数组

时间:2016-08-25 10:07:23

标签: c++ arrays shared-ptr smart-pointers

我想给数组写一些字节。为了利用现代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 在这种情况下有没有办法使用智能指针?

4 个答案:

答案 0 :(得分:10)

不要将std::make_shared与原始数组一起使用,它不会按预期构造数组,但会尝试创建指向您指定类型的指针,即unsigned char[]。这就是使用unsigned char (*)[]时获得get()的原因,如错误消息所示。

默认情况下,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>

答案 1 :(得分:5)

我建议您使用std::vector<unsigned char> vec(512);,包装连续的动态数组正是它的用途。获取原始缓冲区指针就像vec.data();

一样简单

如果需要共享矢量,则仍然可以使用智能指针

auto p_vec = make_shared<vector<unsigned char>>(512);

由于使用了矢量,您将获得引用计数的好处,几乎没有开销,您将获得整个矢量API。

答案 2 :(得分:4)

如果你真的想要使用带有数组的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[]>());

答案 3 :(得分:2)

你不能使用:

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[]运算符可以正确处理缓冲区的释放。