I have a function f
returning a char*
. The function documentation says:
The user must delete returned string
I wa
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.
This code can never be correct:
std::string s(cstring);
delete cstring;
The std::string
constructor that takes a character pointer, requires a NUL-terminated string. So it is multiple characters.
delete cstring
is scalar delete.
Either you are trying to create a string from a character scalar (in which case, why the indirection?)
std::string s(cstring[0]);
delete cstring;
or you have multiple characters, and should delete accordingly
std::string s(cstring);
delete [] cstring;
Check the other answers for the recommended way to make sure delete[]
gets used, e.g.
std::string(std::unique_ptr<char[]>(f()).get())
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 delete
d 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.
std::string steal_char_buffer( std::unique_ptr<char[]> buff ) {
std::string s = buff?buff.get():""; // handle null pointers
return s;
}
std::string steal_char_buffer( const char* str ) {
std::unique_ptr<char[]> buff(str); // manage lifetime
return steal_char_buffer(std::move(buff));
}
now you can type
std::string s = steal_char_buffer(f());
and you get a std::string
out of f()
.
You may want to make the argument of steal_char_buffer
be a const char*&&
. It is mostly pointless, but it might lead to some useful errors.
If you can change the interface of f
, make it return a std::string
directly or a std::unique_ptr<char[]>
.
Another good idea is to wrap f
in another function that returns a std::unique_ptr<char[]>
or std::string
:
std::unique_ptr<char[]> good_f() {
return std::unique_ptr<char[]>(f());
}
and/or
std::string good_f2() {
auto s = good_f();
return steal_char_buffer( std::move(s) );
}