Can you allocate an array with something equivalent to make_shared?
Solution 1
The point of make_shared is to incorporate the managed object into the control block of the shared pointer,
Since you're dealing with C++11, perhaps using a C++11 array would satisfy your goals?
#include <memory>
#include <array>
int main()
{
auto buffer = std::make_shared<std::array<char, 64>>();
}
Note that you can't use a shared pointer the same way as a pointer you'd get from new[], because std::shared_ptr
(unlike std::unique_ptr
, for example) does not provide operator[]
. You'd have to dereference it: (*buffer)[n] = 'a';
Solution 2
Do you need the allocated memory to be shared? You can use a std::unique_ptr
instead and the std::make_unique
available on C++14:
auto buffer = std::make_unique<char[]>(64);
There will be a std::make_shared
version available in C++20:
auto buffer = std::make_shared<char[]>(64);
Solution 3
How about this?
template<typename T>
inline std::shared_ptr<T> MakeArray(int size)
{
return std::shared_ptr<T>( new T[size], []( T *p ){ delete [] p; } );
}
auto buffer = new char[64];
auto buffer = MakeArray<char>(64);
Josh Elias
Updated on January 11, 2022Comments
-
Josh Elias over 2 years
buffer = new char[64]; buffer = std::make_shared<char>(char[64]); ???
Can you allocate memory to an array using
make_shared<>()
?I could do:
buffer = std::make_shared<char>( new char[64] );
But that still involves calling new, it's to my understanding
make_shared
is safer and more efficient. -
Josh Elias over 11 yearsI can't specify the size of the array at compile time though?
-
Cubbi over 11 years@JoshElias You sure can at compile time. Do you mean runtime? That would require your own class that takes array size as a constructor argument, since
make_shared<T>
forwards its runtime arguments to the constructor ofT
. Or just make a shared vector. -
Josh Elias over 11 yearsYes sorry I did mean runtime. Ah..That's an excellent idea, thank you for educating a noob!
-
Quuxplusone over 9 yearsUpvoted for insight, but you should know that
make_shared
isn't just for premature optimization; it's also for exception-safety.std::shared_ptr<T>(new T)
is a red flag because it leaks thenew T
ifshared_ptr
's constructor happens to throw abad_alloc
exception. -
PeteC almost 9 years@Quuxplusone there's no leak. The object is deleted if an exception (e.g. bad_alloc) is thrown.
-
Quuxplusone almost 9 years@PeteC we're both right, in that the problem case is subtler than my terse comment had implied. The problem is with an expression such as
foo(sh_ptr(new T), sh_ptr(new U));
— where there's no sequence point between the calls tosh_ptr
's constructor, so a valid order of construction isnew U
,new T
,sh_ptr(<ptr to T>)
,sh_ptr(<ptr to U>)
. If either of the middle two calls throw, thennew U
is leaked. herbsutter.com/gotw/_102 -
Dongwei Wang over 6 yearsI have a question about the memory release for useing a shared pointer points to a std::array. Shared pointer is not good to delete arrays. we have to define the deleter to make it works correctly. For the code in your reply, if the shared pointer is out of scope, it will automatically delete all memory of std::array<char, 64> of just the first element in std::array<char, 64>.
-
SagiLow over 6 yearsThere is a difference between creating new
shared_ptr
and usingmake_shared
, the later has 1 less atomic operation and it's preferred whenever possible. -
seattlecpp over 4 yearsThis method also doesn't allocate the reference count with the array, so it costs two calls into the memory manager.
-
Tony Wall about 4 yearsConsidering C++20 is around the corner and this "polyfill" allows us to write code very close to what it will look like once your compiler of choice supports C++20's make_shared<T[]>(size_t), the overhead will be greatly outweighed by more clean robust future-proof code. If you rename the template to something like "make_shared_array" it's obvious what the intent was when you come back to your code next year to upgrade it ;-) This helps greatly working with variable structure buffers, as many system calls require. The other variable array methods generate blocking cast warnings=errors.
-
Thomas over 3 yearseven if you do want it shared,
make_unique
will workstd::shared_ptr<char[]> b; b = std::make_unique<char[]>(25);
-
Paul Groke over 3 years@Thomas Yes,
make_unique
will work just fine. But initializing ashared_ptr
that way will cost you an extra memory allocation. Which can be avoided when usingmake_shared
. -
Thomas over 3 years@PaulGroke True, but for completeness sake I'll add that that saved allocation comes with a slight risk weak_ptr, make_shared and memory deallocation
-
yoni over 3 yearsSo you are telling me that if I want a dynamic array of float indeed to: Create my class that inherits from std::array and put that as a parameter for the shred ptr? I'd rather take my chances with float*
-
Cubbi over 3 years@yoni no, a dynamic array of float is called vector<float>. Shared pointers aren't related or relevant.