Move constructor for std::string from char* - c++

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.

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.

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 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) );
}

Related

Construct a string without allocation

Considering we have a struct with char * member, if we want to request the content of this member, we normally do
char const * get_member() { return object.member; }
By this, we only return a pointer, without any allocation.
If now we want to return a string; is it possible to let the string just use that pointer, instead of copying the content and construct a new string object?
string const & get_member() { return object.member; }
will this code above will do a memory allocation. what like of extra work will this method do compare to the char const * one?
No, it is not possible. std::string always allocates its own memory and cannot take ownership of a pre-existing buffer.
You can either return a copy of the pointer, or you can use a std::string member in the first place, and return a reference to it. Or, alternatively return std::string_view which can be used with either char* or a std::string member. String view is only available since C++17 but it also exists in standard library extensions some for earlier compilers and there also exists non-standard implementations.
The struct is from some C code based library, just want to wrap with C++, at the mean time, do not kill any performance.
Then it seems that returning a std::string would not be an appropriate design.

How to return char* from class?

I want to return a name, and while the main should be able to alter it (in main's scope), it should not change in the class.
If I do it like this:
char* get_name(){
char* name = new char[sizeof(_name)+1];
strcpy(_name,name);
return name;
}
do I have to delete[] at some point? And when?
Edit: I don't believe it's the same problem as pointer to local variable since the problem here is how to delete it after i use it.
Well, that's the problem with manual memory management. Indeed, if you want to return a copy, then it would be the caller's responsibility to free the memory, which is extremely error prone. That's why C++ has std::string class which handles the memory;
std::string get_name() const //note the const on member function
{
return _name; //this will work even if _name is char*, btw
}
As others have said, using std::string is probably a better option. If you want to use a char* instead, I would suggest simply returning a const char*:
const char* get_name() {
return _name;
}
You will be returning a const reference, meaning that the calling code should not change it. The way you are doing it, you will indeed have to delete after every call to get_name(), which is not ideal.
You will indeed have to delete[] the returned pointer at some point: since every new[] must be balanced with a delete[]. That can be difficult to manage.
But why not maintain a std::string member in your class, and write
const std::string& getName() const
{
return name; // name is the class member.
}
instead? Returning a const reference obviates a deep copy and also means the caller cannot modify the member.
First of all I think you mean
strcpy( name, _name );
^^^^^^^^^^^
instead of
strcpy( _name, name );
^^^^^^^^^^^
The object of the class that returns the pointer to the dynamically allocated memory will not have access to this memory after returning the pointer.
So it is the client of the function who shall free the allocated memory.
As other already pointed it is better to use standard class std::string in such cases.

'Moving' unchanging char array into const std::string [duplicate]

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.
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.
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 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) );
}

std::vector::push_back parameter by reference

Consider the following source code in C++
vector <char *> myFunction()
{
vector <char *> vRetVal;
char *szSomething = new char[7];
strcpy(szSomething,"Hello!");
vRetVal.push_back(szSomething); // here vRetVal[0] address == &szSomething
delete[] szSomething; // delete[]ing szSomething will "corrupt" vRetVal[0]
szSomething = NULL;
return vRetVal; // here i return a "corrupted" vRetVal
}
Any idea on how to use push_back to make a copy of the parameter I pass instead of taking it by reference? Any other idea is also accepted and appreciated.
The object whose pointer you've pushed to the vector is destroyed by delete statement in your code. That means, the item (which is pointer) in the vector is pointing to a deleted object. I'm sure you don't want that.
Use std::string:
std::vector<std::string> myFunction()
{
std::vector<std::string> v;
v.push_back("Hello");
v.push_back("World");
return v;
}
In C++11, you could just write this:
std::vector<std::string> myFunction()
{
std::vector<std::string> v{"Hello", "World"};
return v;
}
Or this,
std::vector<std::string> myFunction()
{
return {"Hello", "World"};
}
push_back will make a copy of the parameter you pass.
But your parameter is the pointer, not the string itself.
To automatically copy the string, use std::string.
push_back() does make a copy. In your posted code, you're passing a pointer to a null terminated string so C++ makes a copy of the pointer. If want a copy of that string, you have some options:
If you insist on using C style null terminated character arrays as strings, you can simply pass in the pointer and not call delete[]. Of course, since C++ has only manual memory management, you must be sure to call delete[] at a later but appropriate time...
The other option, as everyone else will tell you, is to simply use std::string. It will manage memory for you and will mostly "just work..."
Fail manual memory management is fail- as it always is. Use std::string like a sane person and you will discover that your program actually has a chance in hell of functioning correctly.

C++ char array corruption?

I'm trying to build a function that compacts the sprintf function, but somehow I ran into the following problem:
The first line after calling the class (It used to be a function, but that didn't work either) I get the correct result: http://puu.sh/1m1Bw
But the line after I get something completely different, while I didn't even touch the class or the variable: http://puu.sh/1m1BR
Can someone explain to me what's happening here?
Edit: Forgot the actual class:
StringCreator::StringCreator(char* _parten, ...) {
char buff[255];
va_list args;
va_start (args, _parten);
vsprintf (buff,_parten, args);
va_end(args);
this->str = buff;
}
And in the .h file:
class StringCreator {
public:
StringCreator(char* _parten, ...);
char* str;
};
After the StringCreator() constructor is complete the member variable this->str is a dangling pointer as it is pointing to buff which is a local variable of the constructor. Accessing this->str after the constructor is undefined behaviour. Changing str from a char* to a std::string is a solution and if you need access to a const char* you can use str.c_str(). Using a std::string also means the default copy constructor and assignment operator are correct.
If, as indicated in the comment to this answer, you new char[255] instead of using a std::string, then you need to either make StringCreator non-copyable or implement a copy constructor and assignment operator that copies the content of str. See What is The Rule of Three? Alternatively, you could have char str[255]; and avoid dynamic allocation and default copying of StringCreator would be correct.
To avoid potential buffer overrun on the call to vsprintf() use vsnprintf() instead (if your compiler supports C99) which accepts as an argument the size of the buffer being populated and does not write more than the specified size.