Is There Any Use For Unique_Ptr With Array

Is there any use for unique_ptr with array?

Some people do not have the luxury of using std::vector, even with allocators. Some people need a dynamically sized array, so std::array is out. And some people get their arrays from other code that is known to return an array; and that code isn't going to be rewritten to return a vector or something.

By allowing unique_ptr<T[]>, you service those needs.

In short, you use unique_ptr<T[]> when you need to. When the alternatives simply aren't going to work for you. It's a tool of last resort.

Proper way to create unique_ptr that holds an allocated array

Using the T[] specialisation:

std::unique_ptr<unsigned char[]> testData(new unsigned char[16000]());

Note that, in an ideal world, you would not have to explicitly use new to instantiate a unique_ptr, avoiding a potential exception safety pitfall. To this end, C++14 provides you with the std::make_unique function template. See this excellent GOTW for more details. The syntax is:

auto testData = std::make_unique<unsigned char[]>(16000);

How to make an array that holds unique_ptrs?

std::unique_ptr<int[]> arr;
arr = std::make_unique<int[]> (5);

At this point you have a unique_ptr to an array of int. This sounds like it is exactly what you want.

arr[0] = *new int(1);

But this is questionable. It dynamically allocates a single int, assigns 1 to the allocated int, then it assigns the value, 1, at the allocated int into the array at element 0. the allocated int is left hanging with nothing pointing at it, and is now exceptionally difficult to `delete. This is a memory leak.

delete &arr[0]; // malloc error, want to avoid "delete"

And as you've seen, this is fatal. Rather than attempting to delete the leaked int, delete has been invoked with a pointer to the array stored in the unique_ptr. Eventually the unique_ptrwill try todelete` the array and fail because it's already gone.

Based on comments, OP intends

std::unique_ptr<int*[]> arr;
arr = std::make_unique<int*[]> (5);
arr[0] = new int(1);
delete arr[0];

But I'd like to talk them out of this idea. Let's look at their end goal: a templated class

template <class TYPE>
class MyVector
{
std::unique_ptr<TYPE[]> arr; // array of whatever type
public:
MyVector(size_t size): arr(std::make_unique<TYPE[]> (size))
{

}
TYPE& operator[](size_t index)
{
return arr[index];
}
// note the complete lack of growing, shrinking and other vector goodness
// as they are not needed for this example.
};

We can use this class with just about anything.

int main()
{
// vector of int
MyVector<int> vec(5);
vec[0] = 1;

// vector of pointer to int (yuck)
MyVector<int*> vec2(5);
vec2[0] = new int(1);
delete vec2[0];

// vector of smart pointer to int (also yuck, but less yuck)
MyVector<std::unique_ptr<int>> vec3(5);
vec3[0] = std::make_unique<int>(1);

// vector of std::string
MyVector<std::string> vec4(5);
vec4[0] = "I am the very model of a modern major general...";
}

If the user of the vector want it to contain pointers, they can say so. There is no reason to force the user to use a pointer.

Is it true that unique_ptr which points to an array will automatically free dynamic memory after calling release()?

I looked a little in this, and I'm guessing this was just a mistake on the author's part. cppreference.com makes no reference to any array specialization for release. Just to make sure, I went ahead and checked the source code for libc++ (LLVM's implementation of the standard library). This is the implementation for std::unique_ptr<T[], Deleter>::release. As you can see, it does not call delete[]. My guess is the author meant to write up.reset();, as this does free the memory.

C++ unique_ptr and arrays

This is not working, however, if I delete the constructor of A, it
works.

When you removed the user defined constructor, the compiler implicitly generates a default one. When you provide a user defined constructor, the compiler doesn't implicitly generate a default constructor.

std::make_unique<T[]> requires the use of default constructors...

So, provide one, and all should work well

#include <iostream>  
#include <string>
#include <vector>
#include <functional>
#include <memory>

using namespace std;

class A {
string str;
public:
A() = default;
A(string _str): str(_str) {}
string getStr() {
return str;
}
};

int main()
{
unique_ptr<A[]> ptr = make_unique<A[]>(3);
}

Use unique_ptr for an array, how to view each value in debug mode local or watch tags

I assume the IDE to be visual studio. When you hit a breakpoint where I is in scope, open a Watch window and type I.get(),3 into a new row. get() gives you the raw int* pointer and 3 displays it in the watch as an int[3] array, with all its values listed.

Watch unique_ptr array example VS2017

Inspired by this question. This appears to work with frame pointers both turned on and off.

Can I create an array of unique_ptr<T[]>(n), n declared at runtime, without looping on the elements?

You are using a raw arrays of smart pointers to raw arrays which is not C++ idiomatic. IMHO, std::array<std::vector<int>, 10> MyArray; would be later easier to use. Anyway, the error message is pretty self explanatory: you use the n variable in the lambda function without capturing it. The compiler just requires:

generate_n(std::begin(myArray), 10, [n]{ return std::unique_ptr<int[]>(new int[n]); });

In fact, the correct way to generate a unque_ptr is through make_unique, so the above line should be re-written as (thanks to BenVoigt for noticing):

generate_n(std::begin(myArray), 10, [n]{ return make_unique<int[]>(n); });

Recommended way to make std::unique_ptr of array type without value initialization?

If you really must, just write your own function:

template <typename T>
std::unique_ptr<T> make_unique_uninitialized(const std::size_t size) {
return unique_ptr<T>(new typename std::remove_extent<T>::type[size]);
}

Avoid the temptation to create the unique_ptr directly:

std::unique_ptr<T[]>(new T[size])  // BAD

Because this is not exception-safe in general (for all the usual reasons you use make_unique in the first place - consider function calls with multiple arguments and exceptions thrown about).



Related Topics



Leave a reply



Submit