Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move constructor for std::string from char*

I have a function f returning a char*. The function documentation says:

The user must delete returned string

I want to construct a std::string from it. The trivial things to do is:

char* cstring = f();
std::string s(cstring);
delete cstring;

Is it possibile to do it better using C++ features? I would like to write something like

std::string(cstring)

avoiding the leak.

like image 409
Ruggero Turra Avatar asked Feb 23 '15 18:02

Ruggero Turra


People also ask

What is move constructor in C++?

For non-union class types ( class and struct ), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument. If this satisfies the requirements of a constexpr constructor, the generated move constructor is constexpr .

How do I assign a C string to a std string?

// Assign C string to std:string directly std::cout << mystring << ' '; Show activity on this post. Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question. Provide details and share your research! But avoid … Asking for help, clarification, or responding to other answers.

Is a constructor obligated to move objects in a class?

It is not obligated to move anything, the class is not required to have a resource to be moved and a 'move constructor' may not be able to move a resource as in the allowable (but maybe not sensible) case where the parameter is a const rvalue reference (const T&&).

Is it possible to implement a string constructor with a NUL-terminated string?

Nor is there any guarantee doing so would actually be advantageous, depending on implementation-details. The std::string constructor that takes a character pointer, requires a NUL-terminated string. So it is multiple characters.


2 Answers

std::string will make a copy of the null terminated string argument and manage that copy. There's no way to have it take ownership of a string you pass to it. So what you're doing is correct, the only improvement I'd suggest is a check for nullptr, assuming that is a valid return value for f(). This is necessary because the std::string constructor taking a char const * requires that the argument point to a valid array, and not be nullptr.

char* cstring = f();
std::string s(cstring ? cstring : "");
delete[] cstring;   // You most likely want delete[] and not delete

Now, if you don't need all of std::string's interface, or if avoiding the copy is important, then you can use a unique_ptr to manage the string instead.

std::unique_ptr<char[]> s{f()}; // will call delete[] automatically

You can get access to the managed char * via s.get() and the string will be deleted when s goes out of scope.

Even if you go with the first option, I'd suggest storing the return value of f() in a unique_ptr before passing it to the std::string constructor. That way if the construction throws, the returned string will still be deleted.

like image 187
Praetorian Avatar answered Oct 09 '22 11:10

Praetorian


There is no standard way for a std::string to take ownership of a buffer you pass.

Nor to take responsibility of cleaning up such a buffer.

In theory, an implementation, knowing all the internal details, could add a way for a std::string to take over buffers allocated with their allocator, but I don't know of any implementation which does.
Nor is there any guarantee doing so would actually be advantageous, depending on implementation-details.

like image 33
Deduplicator Avatar answered Oct 09 '22 10:10

Deduplicator