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.
Related
I used to think returning a reference is bad as our returned reference will refer to some garbage value. But this code works (matrix is a class):
const int max_matrix_temp = 7;
matrix&get_matrix_temp()
{
static int nbuf = 0;
static matrix buf[max_matrix_temp];
if(nbuf == max_matrix_temp)
nbuf = 0;
return buf[nbuf++];
}
matrix& operator+(const matrix&arg1, const matrix&arg2)
{
matrix& res = get_matrix_temp();
//...
return res;
}
What is buf doing here and how does it save us from having garbage values?
buf is declared as static, meaning it retains it's value between calls to the function:
static matrix buf[max_matrix_temp];
i.e. it's not created on the stack as int i = 0; would be (a non-static local variable), so returning a reference to it is perfectly safe.
This following code is dangerous, because the memory for the variable's value is on the stack, so when the function returns and we move back up the stack to the previous function, all of the memory reservations local to the function cease to exist:
int * GetAnInt()
{
int i = 0; // create i on the stack
return &i; // return a pointer to that memory address
}
Once we've returned, we have a pointer to a piece of memory on the stack, and with dumb luck it will hold the value we want because it's not been overwritten yet — but the reference is invalid as the memory is now free for use as and when space on the stack is required.
I see no buf declared anywhere, which means it doesn't go out of scope with function return, so it's okay. (it actually looks like it's meant to be matrixbuf which is also fine, because it's static).
EDIT: Thanks to R. Martinho Fernandes for the guess. Of course it is matrix buf, so it makes buf static array in which temporary is allocated to make sure it doesn't get freed when the function returns and therefore the return value is still valid.
This is safe up to a point, but very dangerous. The returned reference
can't dangle, but if client code keeps it around, at some future point,
the client is in for a big surprise, as his value suddenly changes to a
new return value. And if you call get_matrix_temp more than
max_matrix_temp times in a single expression, you're going to end up
overwriting data as well.
In the days before std::string, in code using printf, I used this
technique for returning conversions of user defined types, where a
"%s" specifier was used, and the argument was a call to a formatting
function. Again, max_matrix_temp was the weak point: a single
printf which formatted more instances of my type would output wrong
data. It was a bad idea then, and it's a worse idea now.
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);
}
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.
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.
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.