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()
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.
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;
}
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.
Now I have a function that has to return a string. I saw a particular implementation where he returns a const char * from the function.
Something like this:
const char * GetSomeString()
{
........
return somestlstring.c_str();
}
SomeOtherFoo ()
{
const char * tmp = GetSomeString();
string s = tmp;
}
Now I felt there is something potentially wrong with this. Is my gut feel right? or Is this a perfectly safe code?
Kindly give me ur suggestions. I have a feeling return const char * this way might result in havoc..
Thanks,
Arjun
Depending on what somestlstring is and what is being done there.
If it is a local variable you are returning a pointer into memory that is being released when GetSomeString completes, so it is a dangling pointer and an error.
It all boils down to the lifetime of somestlstring and the operations you perform on it. The pointer returned by .c_str() is guaranteed to be valid only up to the next mutating operation in the string. So if something changes somestlstring from the call to .c_str() and before s is constructed you will be in undefined behavior land.
If you are asking about the lifetime of the const char * returned by the std::string c_str() function, it is valid until you modify the string you obtained it from, or until the string is destroyed. Returning it from a function is OK (though I would say not great practice), provided you bear those two facts in mind.
This is OK under the conditions #Neil elaborated on. However a better way would be to return a reference to the string
string const& GetSomeString()
{
........
return somestlstring;
}
string s = GetSomeString();
Still keeping in mind that ´somestlstring` must not be a local automatic variable but stored somewhere else in a namespace or a class. Otherwise you can return the string by value
string GetSomeString()
{
........
return somestlstring; // can be a local automatic variable
}
string s = GetSomeString();
It's not great - how long does the memory for your string stick around? Who is responsible for deleting it? Does it need to be deleted at all?
You're better off returning a string object that is responsible for allocating and freeing the string memory - this could be a std::string, or a QString (if you're using Qt), or CString (if you're using MFC / ATL).
on a slightly different note, will your string ever be unicode? Most string classes can deal transparently with unicode data, but const char will not...
To add some scenarios in which this would be ok:
somestlstring is a global variable initialized in the same translation unit (.cpp) as GetSomeString()
somestlstring is a non-static class member, and GetSomeString is a member of that class. In that case, the lifetime of the pointer returned must be documented (basically - as others said - until the strign changes or the object is destroyed)
you are returning a char const * to a literal or compile-time initialized string
It depends upon where the somestlstring variable is located.
If it is a variable locale to the GetSomeString() function, then this is plainly wrong. Indeed, the somestlstring variable is destroyed at the end of the function, and thus the const char * points to something that does not exist anymore.
If it is a global variable, then this code is right.
I have a function for which I cannot change the function parameters. I need to return a const reference to a std::string created in this function. I tried to use boost shared_ptr, but this doesn't work. Why? How do I make this work?
const std::string& getVal(const std::string &key) {
boost::shared_ptr<std::string> retVal(new std::string());
... //build retVal string with += operator based on key
return *retVal;
}
You can't return a reference to a local variable from a function with c++. Although in c++0x this is possible.
Allocate the string on the heap and manually cleanup later:
If you cannot change the function's interface, then you will need to create it on the heap and then manually delete it after.
//Remember to free the address that getVal returns
const std::string& getVal(const std::string &key) {
std::string *retVal = new std::string();
... //build retVal string with += operator based on key
return *retVal;
}
Same solution but not manually:
Since the above will eventually lead to a memory leak if you forget to free it manually. I would recommend to wrap this call into a class and use RAII. I.e. in the constructor, call getVal and set a member of this class to point to it. In the destructor of your class you would delete it.
Why the code you gave with shared_ptr does not work:
shared_ptr works via reference counting. Since you are destroying the only shared_ptr object (by scope), there are no references left and the memory will be freed. To get this to work you'd have to return a shared_ptr, but you said you cannot do this.
You would need to return a boost shared_ptr, not a std::string. As soon as the function exits that shared_ptr on the stack will go out of scope and because there's only one reference it will be deleted. You would also need to return a copy not a reference.
You should never return a reference to a stack variable because again, as soon as the function exists it will be deleted.
If you cannot change the return type then the only (icky) option would be to allocate the string on the heap, return a reference to the pointer, and make sure the calling code knows it's a pointer and later deletes it.
E.g.
const std::string& getVal(const std::string &key) {
return *(new std::string("Something"));
}
// get the val, remember we must delete this pointer!
std::string* pString = &getVal("SomeKey");
delete pString;
This is not a boost issue. You cannot return a reference to a local variable, as the variable will cease to exist once the function terminates. In a case like this, you should really return a value. However, one hack you can use is to make the local variable static, but this may well cause concurrency and other problems.
Since you can't change the function's signature, you can return a reference to a static variable:
const std::string& getVal(const std::string &key) {
static std::string retVal;
... //build retVal string with += operator based on key
return retVal;
}
There are serious problems with this approach though. It is inherently not-thread safe. Even if your app is not multi-threaded, it can cause problems depending on how long the caller holds on to the reference.
If your app is not multi-threaded and each call to getVal() immediately uses or copies the string, then you can probably get away with this. But I would strongly recommend just returning a std::string.
Since what you want is the const reference, you could return by value and make the caller receive it with const reference.
Herb Sutter GotW 88
Another point to consider is that the standard allows a compiler to optimize away copies if it is possible. The standard refers to this a copy elision, however most people know it as "Named Return Value Optimisation" see here.
The basic concept is that where possible the compiler will construct the local object directly on to the object that is the result of the function call:
class A {};
A foo () {
A a; // #1
return a;
}
void bar () {
A b = foo(); // #2
}
In the above example 'a' will be constructed in the same location as 'b' in bar, and so when the function returns no copy is needed at all. In conclusion it might be worth while testing your compiler to see if it performs this optimization. The standard reference for this is 12.8/15 if your interested.