std::string getMyString() { return <make a string>; }
...
HANDLE something = OpenSomething(getMyString().c_str(), ...);
I've read Guaranteed lifetime of temporary in C++ and I believe that the temporary string will live until the assignment has been evaluated, i.e. plenty long enough to make this work as expected.
Having once before run into an std::string lifetime-related bug (can't remember what it was) I'd rather double-check...
The destructor for the temporary will not be called until after the function call returns, so what we see here is safe.
However if the called function saves the char* and it ends up being used somehow after OpenSomething has returned, then that's one fine dangling pointer.
Yes, this is fine. :-)
The string will be destroyed at the end of the statement, at the semi colon.
If you don't use any other argument of OpenSomthing for returning pointer to getMyString.c_str() everything will be OK.
Related
I have a
std::string
and pass that by reference to a function.
The function dereferences the parameter (pointer) into a local std::string for ease of working.
I update the local string's value and then update the pointer.
Have I just pointed to something that's gone out of scope? Or have I updated the underlying value of the string pointed to by string abc in the example below?
BTW It works but I'm concerned I'm breaking C++ rules.
int main() {
std::string abc = R"(This is a string "raw" literal)";
updateStringValue(&abc);
log_v(abc.c_str());
}
void updateStringValue(std::string *theData) {
std::string localString = (*theData);
localString.append("some other value");
*theData = localString;
}
I realise that the local string "localString" only survives the function but has the amended value really been retained (or maybe it's still floating around in memory but now out of scope once the function ends)?
I expected this to work (it did) but am having doubts.
Previously I did not dereference the incoming data's pointer into a local string but the resulting syntax was more confusing (to others) so I did it this way to simplify the overall structure.
I've definitely confused myself now.
It works fine. *theData = localString; invokes copy assignment, so the caller's string is changed to be equivalent to (but not the same object as) localData. After that, localData gets cleaned when the function returns, but that's fine, the copy has already occurred.
To be clear, you did not pass by reference (that would be void updateStringValue(std::string& theData), with an &, not a *, and no need for the caller to explicitly take the address of their local variable). Passing-by-reference would save you the need to manually dereference the pointer.
Also note, there's no need to make the copy here. You could just call:
theData->append("some other value");
or if you used a true reference:
theData.append("some other value");
and save the local copy and copy-back entirely.
Apologies as I know similar-looking questions exist, but I'm still not totally clear. Is the following safe?
void copyStr(const char* s)
{
strcpy(otherVar, s);
}
std::string getStr()
{
return "foo";
}
main()
{
copyStr(getStr().c_str());
}
A temporary std::string will store the return from getStr(), but will it live long enough for me to copy its C-string elsewhere? Or must I explicitly keep a variable for it, eg
std::string temp = getStr();
copyStr(temp.c_str());
Yes, it's safe. The temporary from getStr lives to the end of the full expression it appears in. That full expression is the copyStr call, so it must return before the temporary from getStr is destroyed. That's more than enough for you.
A temporary variable lives until the end of the full expression. So, in your example,
copyStr(getStr().c_str());
getStr()’s return value will live until the end of copyStr. It is therefore safe to access its value inside copyStr. Your code is potentially still unsafe, of course, because it doesn’t test that the buffer is big enough to hold the string.
You have to declare a temporary variable and assign to it the return result:
...
{
std::string tmp = getStr();
//tmp live
...
}
//tmp dead
...
A temporary var must have a name, and will live in the scope where it has been declared in.
Edit: it is safe, you pass it by copied value (your edit was heavy, and nullified my above answer. The above answer concern the first revision)
copyStr(getStr().c_str()); will pass the rvalue to copyStr()
can any one tell me .Is there any benefit of passing string as func(string& ) instead of func( string).
Passing an object by reference means, well, that you're passing the reference by value, instead of passing the object by value, which means that you have to made a copy at function invocation.
However, passing-by-reference introduces a new set of questions which you must be aware of:
does the function modifies or not the passed object? If it does not, you should put in the const modifier
does the function need to modify the object, but not exposing the modifications outside the function boundaries? In that case what you really want is a copy.
does the function stores somewhere/somehow the reference of the passed object? In that case, you have to understand how object ownership is passed and when it's safe to delete it. You may want to use smart pointers to deal with these issues
The point is: just because passing-by-reference makes function invocation cheaper does not means that you must use it in any case.
func(string &) passes the string by reference. This means that it will not be copied, and that the function can modify it.
func(string) passes the string by value. This means that a copy will be created, and that the function can only modify it's own local copy of that string.
To pass a string without copying, but prevent it from being modified use func(const string&).
If your function needs to take a copy of the argument anyway, passing by value is preferable.
Passing a reference will usually be more efficient for complex types, but it should be a reference to const unless you want the function to be able to modify it:
void f(string); // function gets its own copy - copying may be expensive
void f(string&); // function can modify the caller's string
void f(string const&); // function can read the caller's string, but not modify it
You can also use func(const string& ) instead of func(string& ) to make sure that the passed-by-reference parameter does not get altered mistakenly inside the function.
When you pass it as string the string first gets copied and the copy is sent to the function. The best way to pass expensive objects such as strings, if you don't want the function to modify them, is by const string&.
The const is important. First of all, it ensures the string won't be modified inside the function. Also, you wouldn't be able to pass a literal to function without using it func("this is a litearal because it isn't inside a variable").
Passing by reference is typically better than passing by value as far as performance is concerned (exclude the built-in data types). So yes func(string&) is better than func(string). Provided that the passed string can be modified when the function finishes. If you don't intend to change the string then use func(const string&).
On the other note, I remember reading somewhere that in STL, the strings are optimized. Means if you pass string by value, it may not necessarily create a new string on heap. So passing by value may not be that much expensive as you expect. e.g.
string s1 = "hello"; // new buffer allocated on heap and copied "hello"
string s2 = s1; // s2 and s1 both 'may' refer to same heap
...
s1 += " world"; // s2 continue referring to old heap ...
// new heap created to accomodate "hello world" referred by s1
Yes. Passing a reference is always efficient.
A string may be stored by value and the copying may take as long as O(n) (i.e., copying takes time proportional to the length of the string). It will also cause heap memory to be allocated, which is usually far more expensive than the copy.
You may also consider passing by reference-to-const i.e. func(const string &) to avoid any unintenional changes.
You can also try to use rvalue reference optimizations by using move semantics.
void func(string &&s)
{
myS = std::move(s);
}
I'm fairly novice with C++'s strings so the following pattern may be a little fugly. I'm reviewing some code I've written before beginning integration testing with a larger system. What I'd like to know is if it is safe, or if it would be prone to leaking memory?
string somefunc( void ) {
string returnString;
returnString.assign( "A string" );
return returnString;
}
void anotherfunc( void ) {
string myString;
myString.assign( somefunc() );
// ...
return;
}
The understanding I have is that the value of returnString is assigned to a new object myString and then the returnString object is destroyed as part of resolving the call to somefunc. At some point in the future when myString goes out of scope, it too is destroyed.
I would have typically passed a pointer to myString into somefunc() and directly assigned to values to myString but I'm striving to be a little clearer in my code ( and relying on the side effect function style less ).
Yes, returning a string this way (by value) is safe,albeit I would prefer assigning it this way:
string myString = somefunc();
This is easier to read, and is also more efficient (saving the construction of an empty string, which would then be overwritten by the next call to assign).
std::string manages its own memory, and it has properly written copy constructor and assignment operator, so it is safe to use strings this way.
Yes by doing
return returnString
You are invoking the string's copy constructor. Which performs a copy* of returnString into the temporary (aka rValue) that takes the place of "somefunc()" in the calling expression:
myString.assign( somefunc() /*somefunc()'s return becomes temporary*/);
This is in turn passed to assign and used by assign to perform a copy into myString.
So in your case, the copy constructor of string guarantees a deep copy and ensures no memory leaks.
* Note this may or may not be a true deep copy, the behavior of the copy constructor is implementation specific. Some string libraries implement copy-on-write which has some internal bookkeeping to prevent copying until actually needed.
You're completely safe because you're returning the string by value, where the string will be "copied", and not by reference. If you were to return a std::string &, then you'd be doing it wrong, as you'd have a dangling reference. Some compilers, even, might perform return value optimization, which won't even really copy the string upon return. See this post for more information.
Yes, it's (at least normally) safe. One of the most basic contributions of almost any reasonable string class is the ability to act like a basic value for which normal assignment, returns, etc., "just work".
As you said a string returnStringis created inside somefunc and a copy is given back when the function returns. This is perfectly safe.
What you want is to give a reference to myString to somefunc (don't use pointer). It will be perfectly clear:
void somefunc( string& myString ) {
myString.assign( "A string" );
}
void anotherfunc( void ) {
string myString;
somefunc(myString);
// ...
return;
}
Say you have a class which is a global (e.g. available for the runtime of the app)
class MyClass {
protected:
std::string m_Value;
public:
MyClass () : m_Value("hello") {}
std::string value() { return m_Value; }
};
MyClass v1;
Using the first form gives me odd behavior when I do
printf("value: %s\n", v1.value().c_str());
It looks as though the string disappears from memory before printf can use it.
Sometimes it prints value: hello other times it crashes or prints nothing.
If I first copy the string like so
std::string copiedString = v1.value();
printf("value: %s\n", copiedString.c_str());
things do work.
Surely there must be a way to avoid doing this with a temporary string.
Edit: So the consensus is to go with a const std::string & return value.
I know everyone says that the original code should be fine but I can tell you that I've seen MSVC 2005 on Windows CE having trouble with it, but only on the CE box. Not the Win32 cross compile.
Your code should work fine. Something else is wrong, that we can't detect from this testcase. Perhaps run your executable through valgrind to search for memory errors.
Well, there's nothing wrong with the code (as I interpret it). It is not optimal and surely not The Right Way (R), you should modify your code like villentehaspam suggests. As it is now, your code makes a copy of the string m_value because you return by value, which is not as good as only returning a const reference.
If you provide a complete code sample that shows the problem, I could help you better.
not that it matters but that std::string return in that class can use a const else wise you're just creating a copy of the member value which is a waste.
std::string value() const { return m_value; }
Here's what's typically happening when you write:
printf("value: %s\n", v1.value().c_str());
The compiler makes a temporary std::string to hold the value returned from v1.value().
It calls v1.value() and puts its return value in the temporary string (exactly how it does this can vary: typically it will pass a reference to the temporary as a hidden parameter to the method. See http://en.wikipedia.org/wiki/Return_value_optimization for discussion).
It calls .c_str() on the temporary std::string, it stashes the const char * result away somewhere (e.g. a register).
It's now finished with the temporary std::string, so destroys it (i.e. calls its destructor, maybe frees some stack space).
It passes the const char * pointer it got in step (3) as an argument to printf().
The problem is that the pointer in step 3 points to memory allocated by the temporary std::string, which gets freed when the temporary's destructor is called. This memory can be long gone by the time it gets used by printf().
Basically, any usage like the one you've shown is dangerous and should be avoided. Using the following is correct:
std::string copiedString = v1.value();
printf("value: %s\n", copiedString.c_str());
because the destructor for copiedString doesn't get called until copiedString goes out of scope, some time after printf() has returned. In fact, this is no less efficient than v1.value().c_str(), because a temporary std::string gets created in either case.
Returning a reference to a string is a fine alternative, provided that the reference remains valid for as long as the caller needs it to. So, a reference to a member variable in a long-lived object is OK; a reference to something which turns out to be temporary isn't.