std::vector::push_back parameter by reference - c++

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.

Related

Can a char* be moved into an std::string?

Say I have something like this
extern "C" void make_foo (char** tgt) {
*tgt = (char*) malloc(4*sizeof(char));
strncpy(*tgt, "foo", 4);
}
int main() {
char* foo;
make_foo(&foo);
std::string foos{{foo}};
free(foo);
...
return 0;
}
Now, I would like to avoid using and then deleting the foo buffer. I.e., I'd like to change the initialisation of foos to something like
std::string foos{{std::move(foo)}};
and use no explicit free.
Turns out this actually compiles and seems to work, but I have a rather suspicious feel about it: does it actually move the C-defined string and properly free the storage? Or does it just ignore the std::move and leak the storage once the foo pointer goes out of scope?
It's not that I worry too much about the extra copy, but I do wonder if it's possible to write this in modern move-semantics style.
std::string constructor #5:
Constructs the string with the contents initialized with a copy of
the null-terminated character string pointed to by s. The length of
the string is determined by the first null character. The behavior is
undefined if s does not point at an array of at least
Traits::length(s)+1 elements of CharT, including the case when s is a
null pointer.
Your C-string is copied (the std::move doesn't matter here) and thus it is up to you to call free on foo.
A std::string will never take ownership.
tl;dr: Not really.
Pointers don't have any special move semantics. x = std::move(my_char_ptr) is the same as x = my_char_ptr. They are not similar in that regard to, say, std::vector's, in which moving takes away the allocated space.
However, in your case, if you want to keep existing heap buffers and treat them as strings - it can't be using std::string's, as they can't be constructed as a wrapper of an existing buffer (and there's small-string optimization etc.). Instead, consider either implementing a custom container, e.g. with some string data buffer (std::vector<char>) and an std::vector<std::string_view>, whose elements point into that buffer.

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

'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::string loses value when passed in function inside a class object

I am really confused how compiler allocates STL objects. Consider the following code:
#include <string>
using namespace std ;
class s {
public:
string k ;
s(string k) : k(k) {}
} ;
void x ( s obj ) {
string k = (obj.k) ;
k += "haha" ;
}
int main () {
std::string mystr ("laughter is..") ;
s mys(mystr) ;
x(mys) ;
printf ("%s", mystr.c_str() ) ;
}
The output of this program is laughter is.. and I expect the output to be:
laughter is haha
Why doesn't mystr string get haha . I need to store it in a class as a part of my code.
If I had passes mystr by value to function x, the string mystr would have got haha into it.
a) How and when do STL objects get allocated? I supposed mystr is on a stack and must be accessible to all functions called from main() .
b) What if I need to store STL objects in a old fashioned Linked list which needs "void*". Cant I just do:
std::string mystr ("mystring.." );
MyList.Add((void*)&mystr) ;
fun(MyList) ;
Can the function fun, now use and modify mystr by accessing MyList ?
c) As an alternative to (b) , can I use pass by reference. The issue is can I declare a class to keep a reference of mystr? I mean the constructor of MyList can be like this:
class MyList {
string& mStr ;
...
};
MyList::MyList ( string& mystr ) {
mStr = mystr ;
}
Is that constructor valid ? Is that class valid?
Your class is just complicating the situation for you. You have exactly the same problem here:
void x ( string str ) {
str += "haha" ;
}
int main () {
std::string mystr ("laughter is..") ;
x(mystr) ;
printf ("%s", mystr.c_str() ) ;
}
I've gotten rid of the class. Instead of putting mystr into an s object and passing the s object to x, I just pass mystr directly. x then attempts to add "haha" to the string.
The problem is that x takes its argument by value. If you pass an object by value, you are going to get a copy of it. That is, the str object is a different object to mystr. It's a copy of it, but it's a different object. If you modify str, you're not going to affect mystr at all.
If you wanted x to be able to modify its argument, you'd need to make it take a reference:
void x ( string& str ) {
str += "haha" ;
}
However, I understand why you introduced the class. You're thinking "Well if I give the string to another object and then pass that object along, the string should be the same both outside and inside the function." That's not the case because your class is storing a copy of the string. That is, your class has a member string k; which will be part of any object of that class type. The string k isn't the same object as mystr.
If you want to modify objects between functions, then you need some form of reference semantics. That means using pointers or references.
As for your questions:
Yes, the string object mystr is on the stack. That has nothing to do with it coming from the standard library though. If you write a declaration inside a function, that object is going to be on the stack, whether it's int x;, string s;, SomeClass c;, or whatever.
The internal storage of data inside mystr is, on the other hand, dynamically allocated. It has to be because the size of a std::string can vary, but objects in C++ always have fixed size. Some dynamic allocation is necessary. However, you shouldn't need to care about this. This allocation is encapsulated by the class. You can just treat mystr as a string.
Please don't use a linked list that stores void*s. Use std::list instead. If you want a linked list of strings, you want std::list<std::string>. But yes, if you have an object that stores pointers to some other objects and you pass that object around by value, the pointers in the copies will still be pointing at the same locations, so you can still modify the objects that they point to.
If you have a std::list<std::string> and you want to pass it to a function so that the function can modify the contents of the container, then you need to pass it by reference. If you also need the elements of the list to be references to the objects you created outside the list, you need to use a std::list<std::reference_wrapper> instead.
As far as initialising a reference member is concerned, you need to use a member initialisation list:
MyList::MyList(string& mystr)
: mStr(mystr)
{ }
The string k that you manipulate in your function x is a copy of the string k in your object obj. And obj itself is already a copy of what you pass and the string you pass and store in obj is also already a copy. So it's very, very far from the original mystr that you expect to being altered.
To your other questions:
a) Yes, objects in this way are stack allocated. Not just stl, any objects. Otherwise you need to use new.
b) No you cannot pass it like this, since it's stack allocated the memory will become invalid. You need to heap allocate it using new.
c) Yes you can pass by reference, but again, it's important where you allocate things.
As others point out, those are some very basic questions and you need t read about heap vs stack allocation and pass by reference and pass by value first and then have a look at some basic STL classes and containers.
Strictly speaking, your question has nothing to do with the STL, even if you accept "STL" as a synonym for the correct "containers, iterators and algorithms of the C++ standard library". std::string was at one point of is history made to appear like a container (a container of characters, that is), but it is generally used in quite a different fashion than "real" container classes like std::vector or std::set.
Anyway,
Why doesnt mystr string get "haha"
Because you don't use references. x modifies a copy of the argument; likewise, string k = (obj.k) creates a copy of the string. Here is the code with references:
void x ( s &obj ) {
string &k = (obj.k) ;
k += "haha" ;
}
a) How and when do STL objects get allocated?
The container object itself is allocated as you define it. How it allocates memory internally is defined by its allocator template parameter, by default std::allocator. You don't really want to know the internals of std::allocator - it almost always does the right thing. And I don't think your question is about internal allocations, anyway.
I supposed mystr is on a stack and must be accessible to all functions called from main()
Yes.
b) What if I need to store STL objects in a old fashioned Linked list
which needs "void*".
Use std::list<void*>.
But you don't have to do this. Use std::list<std::string> and you likely won't need pointers in your code at all.
As for your further code examples:
std::string mystr ("mystring.." );
MyList.Add((void*)&mystr) ;
fun(MyList) ;
Can the function fun, now use and modify mystr by accessing MyList ?
Yes. However, the code has two problems. The smaller one is (void*)&mystr. Generally, you should avoid C-style casts but use one of static_cast, reinterpret_cast, const_cast or dynamic_cast, depending on which conversion you need. And in this piece of code, you don't need a cast at all, anyway.
The bigger problem is adding the address of a local variable to something which looks like it expects dynamically allocated objects. If you return MyList from a function, mystr will be destroyed and the copied list will contain a pointer to a dead object, eventually leading to undefined results.
In order to solve this, you have to learn more about new, delete and, possibly, smart pointers. This is beyond the scope of a simple answer, and the outcome would probably still be worse than std::list<std::string>.
The issue is can I declare a class to keep a reference of mystr?
Yes, but you should generally avoid it, because it easily leads to dangling references, i.e. references to dead objects, for the reasons explained above.
class MyList {
string& mStr ;
...
};
MyList::MyList ( string& mystr ) {
mStr = mystr ;
}
Is that constructor valid ?
No, it won't compile. You'd need to use an initialisation list:
MyList::MyList ( string& mystr ) : myStr(mystr) {}
I can only repeat my recommendation from above. Use std::list<std::string>.

Prototype for function that allocates memory on the heap (C/C++)

I'm fairly new to C++ so this is probably somewhat of a beginner question. It regards the "proper" style for doing something I suspect to be rather common.
I'm writing a function that, in performing its duties, allocates memory on the heap for use by the caller. I'm curious about what a good prototype for this function should look like. Right now I've got:
int f(char** buffer);
To use it, I would write:
char* data;
int data_length = f(&data);
// ...
delete[] data;
However, the fact that I'm passing a pointer to a pointer tips me off that I'm probably doing this the wrong way.
Anyone care to enlighten me?
In C, that would have been more or less legal.
In C++, functions typically shouldn't do that. You should try to use RAII to guarantee memory doesn't get leaked.
And now you might say "how would it leak memory, I call delete[] just there!", but what if an exception is thrown at the // ... lines?
Depending on what exactly the functions are meant to do, you have several options to consider. One obvious one is to replace the array with a vector:
std::vector<char> f();
std::vector<char> data = f();
int data_length = data.size();
// ...
//delete[] data;
and now we no longer need to explicitly delete, because the vector is allocated on the stack, and its destructor is called when it goes out of scope.
I should mention, in response to comments, that the above implies a copy of the vector, which could potentially be expensive. Most compilers will, if the f function is not too complex, optimize that copy away so this will be fine. (and if the function isn't called too often, the overhead won't matter anyway). But if that doesn't happen, you could instead pass an empty array to the f function by reference, and have f store its data in that instead of returning a new vector.
If the performance of returning a copy is unacceptable, another alternative would be to decouple the choice of container entirely, and use iterators instead:
// definition of f
template <typename iter>
void f(iter out);
// use of f
std::vector<char> vec;
f(std::back_inserter(vec));
Now the usual iterator operations can be used (*out to reference or write to the current element, and ++out to move the iterator forward to the next element) -- and more importantly, all the standard algorithms will now work. You could use std::copy to copy the data to the iterator, for example. This is the approach usually chosen by the standard library (ie. it is a good idea;)) when a function has to return a sequence of data.
Another option would be to make your own object taking responsibility for the allocation/deallocation:
struct f { // simplified for the sake of example. In the real world, it should be given a proper copy constructor + assignment operator, or they should be made inaccessible to avoid copying the object
f(){
// do whatever the f function was originally meant to do here
size = ???
data = new char[size];
}
~f() { delete[] data; }
int size;
char* data;
};
f data;
int data_length = data.size;
// ...
//delete[] data;
And again we no longer need to explicitly delete because the allocation is managed by an object on the stack. The latter is obviously more work, and there's more room for errors, so if the standard vector class (or other standard library components) do the job, prefer them. This example is only if you need something customized to your situation.
The general rule of thumb in C++ is that "if you're writing a delete or delete[] outside a RAII object, you're doing it wrong. If you're writing a new or `new[] outside a RAII object, you're doing it wrong, unless the result is immediately passed to a smart pointer"
In 'proper' C++ you would return an object that contains the memory allocation somewhere inside of it. Something like a std::vector.
Your function should not return a naked pointer to some memory. The pointer, after all, can be copied. Then you have the ownership problem: Who actually owns the memory and should delete it? You also have the problem that a naked pointer might point to a single object on the stack, on the heap, or to a static object. It could also point to an array at these places. Given that all you return is a pointer, how are users supposed to know?
What you should do instead is to return an object that manages its resource in an appropriate way. (Look up RAII.) Give the fact that the resource in this case is an array of char, either a std::string or a std::vector seem to be best:
int f(std::vector<char>& buffer);
std::vector<char> buffer;
int result = f(buffer);
Why not do the same way as malloc() - void* malloc( size_t numberOfBytes )? This way the number of bytes is the input parameter and the allocated block address is the return value.
UPD:
In comments you say that f() basically performs some action besides allocating memory. In this case using std::vector is a much better way.
void f( std::vector<char>& buffer )
{
buffer.clear();
// generate data and add it to the vector
}
the caller will just pass an allocated vector:
std::vector buffer;
f( buffer );
//f.size() now will return the number of elements to work with
Pass the pointer by reference...
int f(char* &buffer)
However you may wish to consider using reference counted pointers such as boost::shared_array to manage the memory if you are just starting this out.
e.g.
int f(boost::shared_array<char> &buffer)
Use RAII (Resource Acquisition Is Initialization) design pattern.
http://en.wikipedia.org/wiki/RAII
Understanding the meaning of the term and the concept - RAII (Resource Acquisition is Initialization)
Just return the pointer:
char * f() {
return new char[100];
}
Having said that, you probably do not need to mess with explicit allocation like this - instead of arrays of char, use std::string or std::vector<char> instead.
If all f() does with the buffer is to return it (and its length), let it just return the length, and have the caller new it. If f() also does something with the buffer, then do as polyglot suggeted.
Of course, there may be a better design for the problem you want to solve, but for us to suggest anything would require that you provide more context.
The proper style is probably not to use a char* but a std::vector or a std::string depending on what you are using char* for.
About the problem of passing a parameter to be modified, instead of passing a pointer, pass a reference. In your case:
int f(char*&);
and if you follow the first advice:
int f(std::string&);
or
int f(std::vector<char>&);
Actually, the smart thing to do would be to put that pointer in a class. That way you have better control over its destruction, and the interface is much less confusing to the user.
class Cookie {
public:
Cookie () : pointer (new char[100]) {};
~Cookie () {
delete[] pointer;
}
private:
char * pointer;
// Prevent copying. Otherwise we have to make these "smart" to prevent
// destruction issues.
Cookie(const Cookie&);
Cookie& operator=(const Cookie&);
};
Provided that f does a new[] to match, it will work, but it's not very idiomatic.
Assuming that f fills in the data and is not just a malloc()-alike you would be better wrapping the allocation up as a std::vector<char>
void f(std::vector<char> &buffer)
{
// compute length
int len = ...
std::vector<char> data(len);
// fill in data
...
buffer.swap(data);
}
EDIT -- remove the spurious * from the signature
I guess you are trying to allocate a one dimensional array. If so, you don't need to pass a pointer to pointer.
int f(char* &buffer)
should be sufficient. And the usage scenario would be:
char* data;
int data_length = f(data);
// ...
delete[] data;