viliam
viliam

Reputation: 13

Proper unique_ptr declaration of 1 element allocated array

I need to use an API as part of a project that includes a class called ParamSet with a method that is defined as the following:

void AddString(const std::string &, std::unique_ptr<std::string[]> v, int nValues);

The purpose of the method is to add an array of strings to the object to describe some parameter. For example a ParamSet object could require a "filename" parameter that points to an array of a nValues strings.

However, when I try and pass the method a unique_ptr to an array containing only 1 string, the code seg faults upon calling the destructor for the ParamSet object unless I define the unique_ptr in a specific way.

The following code causes a seg-fault upon calling Clear() or on return.

ParamSet badparam;
badparam.AddString("filename", unique_ptr<string[]> (new string("test")), 1);
badparam.Clear(); // <------ CAUSES SEG FAULT

However the following does not cause a seg fault.

ParamSet testparam;
std::unique_ptr<std::string[]> strings(new std::string[0]); // DOH, should be string[1]
strings[0] = std::string("test");
testparam.AddString("filename", std::move(strings), 1);
testparam.Clear(); // <------ NO SEG FAULT

I don't understand why creating the unique_ptr in the line calling AddString leads to a seg fault, but creating it outside of the call to does not.

Upvotes: 1

Views: 68

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 596397

The array specialization of std::unique_ptr requires the array to be allocated with new[], as it uses delete[] by default to free the array.

In your first example, you are allocating a single std::string object with new, not a 1-element array with new[].

In your second example, you are allocating a 0-element std::string array, but you need a 1-element array instead.

Try this instead:

std::unique_ptr<std::string[]> strings(new std::string[1]); // <-- NOT 0!
// Or, if you are using C++14:
// auto strings = std::make_unique<string[]>(1);
strings[0] = "test";
testparam.AddString("filename", std::move(strings), 1);

Alternatively:

testparam.AddString("filename", std::unique_ptr<std::string[]>(new std::string[1]{"test"}), 1);

Upvotes: 0

M.M
M.M

Reputation: 141598

The problem is that you use non-array new to allocate memory managed by unique_ptr<T[]> which will then go on to use array delete[], causing undefined behaviour.

The syntax could be:

badparam.AddString("filename", std::unique_ptr<std::string[]>(new std::string[1]{"test"}), 1);

Upvotes: 1

Related Questions