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
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.
Say I have a variable
std::string str; // initialized with some value
And a struct defined as:
struct test
{
public:
const char* name;
};
I know this can be done :
test t1;
t1.name = str.c_str();
But this will store the address of the variable str in t1.name
Instead I want the values of str to put in a char array member of the structure which should be of exact same size as variable str.
Is there a way that can be achieved or a better design
Thanks in advance!
But this will store the address of the variable str in t1.name
Not exactly. str.c_str() does not return the address of variable str. It returns the address of the character array owned by str.
Instead I want the values of str to put in a char array member of the structure
To do that, the structure must have a char array member. Your structure does not; it has a pointer member.
char array member of the structure which should be of exact same size as variable str.
This is not possible. The size of the string is dynamic i.e. it may change at run time. The size of a member array must be known at compile time.
You can instead allocate an array dynamically. As the name implies, the size of dynamic allocation may be determined at run time. However, dynamic allocations must be manually deallocated, or else your program will leak memory.
or a better design
A popular design pattern for dynamic allocation is RAII. The standard library already has a RAII container for character strings: std::string. So, to copy a string into a member of a struct, a good design is to have a string as the member:
struct test {
std::string name;
};
test t1;
t1.name = str;
There is no reason to use const char *, since its more error-prone and harder to implement you should use std::string instead.
std::string also allows you to get const char * to string using c_str() method.
But if you have to implement name as C-style string, here is what you have to do:
Allocate enough space on heap using new.
Cast to non-const
Copy strings using strcpy
Free memory in destructor
Constructor:
test(const std::string& str) : name(new char[str.length() + 1])
{
strcpy((char*)name, str.c_str()); }
};
[Live demo]
Also as #Pixelchemist correctly noted, there are important rules of zero/three/five. If your class contains resources which arent copied/destructed correctly them self, like pure pointers aren't (if you would use smart pointers, it would be different story), you have to implement these as well:
copy constructor
copy assignment operator
destructor
move constuctor
move assignment operator
For extended informations read this excellent answer about rule of three.
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.
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) );
}
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.