Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrap dynamic array with shared_ptr by make_shared

I want to write some bytes to an array. To make use of modern C++ I have decided to use a smart pointer.

#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);
}

However, I am receiving the following compilation error:

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);

I am using g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609 Is there a way to use smart pointers in such a situation?

like image 624
robert Avatar asked Aug 25 '16 10:08

robert


4 Answers

I recommend you use std::vector<unsigned char> vec(512);, wrapping contiguous dynamic arrays is exactly what it's for. Getting the raw buffer pointer is as simple as vec.data();

If the vector needs to be shared, than you can still use a smart pointer

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

You'll get the benefit of reference counting with virtually no overhead due to using vector, and you'll get the entire vector API.

like image 162
StoryTeller - Unslander Monica Avatar answered Oct 28 '22 00:10

StoryTeller - Unslander Monica


You cannot use:

std::make_shared<unsigned char[]>(512);

That because there is no template specialization for Type[]. That because actually std::shared_ptr<T> does not support operator[] yet. It will in the new standard C++17:

operator[] (C++17)


A solution it could be using a STL container, or IMO better: std::unique_ptr.

Indeed, std::unique_ptr supports operator[].

Since C++14, you can:

auto buffer = std::make_unique<unsigned char[]>(512);
buffer[index];

It's exception-safe, almost 0 overhead, and it can be use as a array buffer.

Moreover the deallocation of the buffer is correctly handled by the correct call of delete[] operator.

like image 27
BiagioF Avatar answered Sep 21 '22 05:09

BiagioF


Don't use std::make_shared with raw array, it won't construct an array as you expected, but will try to create a pointer to the type you specified, i.e. unsigned char[]. That's why you get a unsigned char (*)[] when use get(), as the error message said.

And std::shared_ptr will delete the pointer by delete by default, not delete[], which should be used for array. You need to specify a customized deleter for it, but std::make_shared does not allow you to specify it.

You could (1) Initialize std::shared_ptr directly and specify the deleter, like

std::shared_ptr<unsigned char> buf(new unsigned char[512], [](unsigned char* p)
{
    delete[] p;
}); 

(2) Use std::unique_ptr instead, which provides a specified version for array, including call delete[] when deallocating and providing operator[] (std::shared_ptr will support it from C++17).

auto buf = std::make_unique<unsigned char[]>(512);

(3) Consider about std::vector<unsigned char> and std::array<unsigned char>.

like image 13
songyuanyao Avatar answered Oct 28 '22 01:10

songyuanyao


If you really want to use a shared_ptr with an array for this (rather than a vector as suggested by StoryTeller), your type should be unsigned char rather than unsigned char[]. To make sure the array is correctly deleted, you need to specify an array deleter to pass to the shared_ptr constructor (so you can't use make_shared as this doesn't allow you to specify the deleter):

auto buf = std::shared_ptr<unsigned char>(new unsigned char[512], std::default_delete<unsigned char[]>());
like image 6
Smeeheey Avatar answered Oct 27 '22 23:10

Smeeheey