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?
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.
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.
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>
.
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[]>());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With