void fn(string &s)
{
//....
}
//use the function
fn("helloworld");
Firstly, it's wrong to initiate a non-const string with a const char string.
After I add const in the parameter, it compiles.
But is it right to reference a temporary object string("helloworld") on stack?
Is it sure that string("helloworld") gets called?
--
edits.
If a temporary string is created, how the compiler judges that the object string("helloworld") is const from the constructor of std::string(const char*)?
But is it right to reference a temporary object string("helloworld") on stack?
Yes, as long as the reference is const, the lifetime of the temporary will be extended.
Is it sure that string("helloworld") gets called?
Yes, a temporary is created using the conversion constructor std::string(const char*). Note however that the compiler can optimize this step out.
But is it right to reference a temporary object string("helloworld")
on stack?
In this case, probably, but you do have to pay attention to the lifetime of the object. The temporary will cease to exist at the end of the full expression; if fn saves a pointer or a reference to it, you're in trouble. This is typically not a problem with a free function, like your fn (but it can be); it could be a problem if the temporary were an argument to a constructor in a new expression (but the author of the class should document any lifetime requirements which go beyond the constructor invocation).
But is it right to reference a temporary object string("helloworld") on stack?
Yes, why not?
Is it sure that string("helloworld") gets called?
Yes, as long string provides an implicit constructor using a const char* argument this is garuanteed (std::string does so).
Related
Let's consider the following functions:
void processString1(const string & str) { /** **/}
void processString2(string && str) { /** **/}
processString1("Hello");
processString2("Hello");
As I assume, processString1 will invoke copy constructor and processString2 a move constructor of string. What is more efficient?
Your understanding is misguided here.
First, neither of those functions take a value - they both take a reference. So, when an object is passed to either one, no constructor is called - whatever object is passed is simply bound to a reference.
However, your function calls pass a C-string - and there is an implicit conversion from a C-string to a std::string.
Thus, each one will construct a TEMPORARY std::string our of the C-string "Hello".
That temporary object will bind to a reference-to-const in the first case and a rval-reference-to-non-const in the second case.
The language guarantees that the lifetime of the temporary will exist for at least the lifetime of the function call.
Neither function call does any construction - the only construction happens when the C-string is implicitly converted to an instance of std::string.
I've been studying rvalue references (a new concept for me), and am puzzled by a warning I receive in the following class function...
string&& Sampler::Serial() const {
stringstream ss;
.
. [assemble a string value using data members]
.
return ss.str();
}
This compiles successfully, but with the following warning...
..\Metrics\Sampler.cpp:71:16: warning: returning reference to temporary [-Wreturn-local-addr]
return ss.str();
^
I'm fully aware that I'm returning a temporary, as evidenced by the fact that I'm using an rvalue reference as my return type. The code seems to run fine upon execution, so why should this warrant a compiler warning?
The standard answer to similar questions seems to be to copy the return value instead of using a reference, but why should I copy potentially massive amounts of temporary data when I can move it with an rvalue reference? Isn't that why it was invented?
You're not moving your data. You're creating a local object, creating a reference to that local object, destroying that local object, and then still using that reference.
You should return by value, as you already found. But instead of copying, move the data. That's the safe way of ensuring you don't copy those massive amounts of data.
std::string Sampler::Serial() const {
std::stringstream ss;
.
. [assemble a string value using data members]
.
return std::move(ss.str());
}
Note: the std::move is technically redundant here, as ss.str() already returns an rvalue and so would already be moved. I recommend leaving it in anyway. This way works in any situation, so you don't have to think about which form to use: if you want to move, write move.
As pointed out by T.C., in general, though not in your case, this can prevent RVO. In cases where RVO is possible and where the compiler would implicitly use a move anyway, there is no need to write move explicitly. For instance:
std::string f() {
std::string x;
...
return x; // not std::move(x)
}
Here, it should already be clear to the reader that x is a local variable. It's normal for C++ code to return local variables without writing move, because either the compiler will elide the x local variable entirely and construct the std::string object directly in the return slot (whatever that means for your platform), or the compiler will use the move constructor of std::string implicitly anyway.
This is analogous to returning an lvalue reference to a local variable and puts you on the fast-track to undefined behaviour.
Regardless of whether you return an lvalue reference or an rvalue reference, you are still referencing memory which is going to be destroyed on function exit.
Rvalue reference return types should be reserved for cases when you are referencing an object which has a lifetime longer than the function, but you don't need it anymore, so are fine with it being moved-from for efficiency. For example, you might have a case in which you are temporarily storing some data, but clients can choose to "steal" the data from you. Returning an rvalue reference to the data would be reasonable in that case.
You return a (rvalue) reference to object (return by str()) of temporary object (ss) which is destroyed at end of scope.
You should return object instead:
string Sampler::Serial() const
Consider the following code:
class Foo
{
private:
const string& _bar;
public:
Foo(const string& bar)
: _bar(bar) { }
const string& GetBar() { return _bar; }
};
int main()
{
Foo foo1("Hey");
cout << foo1.GetBar() << endl;
string barString = "You";
Foo foo2(barString);
cout << foo2.GetBar() << endl;
}
When I execute this code (in VS 2013), the foo1 instance has an empty string in its _bar member variable while foo2's corresponding member variable holds the reference to value "You". Why is that?
Update: I'm of course using the std::string class in this example.
For Foo foo1("Hey") the compiler has to perform a conversion from const char[4] to std::string. It creates a prvalue of type std::string. This line is equivalent to:
Foo foo1(std::string("Hey"));
A reference bind occurs from the prvalue to bar, and then another reference bind occurs from bar to Foo::_bar. The problem here is that std::string("Hey") is a temporary that is destroyed when the full expression in which it appears ends. That is, after the semicolon, std::string("Hey") will not exist.
This causes a dangling reference because you now have Foo::_bar referring to an instance that has already been destroyed. When you print the string you then incur undefined behavior for using a dangling reference.
The line Foo foo2(barString) is fine because barString exists after the initialization of foo2, so Foo::_bar still refers to a valid instance of std::string. A temporary is not created because the type of the initializer matches the type of the reference.
You are taking a reference to an object that is getting destroyed at the end of the line with foo1. In foo2 the barString object still exist so the reference remains valid.
Yeah, this is the wonders of C++ and understanding:
The lifetime of objects
That string is a class and literal char arrays are not "strings".
What happens with implicit constructors.
In any case, string is a class, "Hey" is actually just an array of characters. So when you construct Foo with "Hey" which wants a reference to a string, it performs what is called an implicit conversion. This happens because string has an implicit constructor from arrays of characters.
Now for the lifetime of object issue. Having constructed this string for you, where does it live and what is its lifetime. Well actually for the value of that call, here the constructor of Foo, and anything it calls. So it can call all sorts of functions all over and that string is valid.
However once that call is over, the object expires. Unfortunately you have stored within your class a const reference to it, and you are allowed to. The compiler doesn't complain, because you may store a const reference to an object that is going to live longer.
Unfortunately this is a nasty trap. And I recall once I purposely gave my constructor, that really wanted a const reference, a non-const reference on purpose to ensure exactly that this situation did not occur (nor would it receive a temporary). Possibly not the best workaround, but it worked at the time.
Your best option really most of the time is just to copy the string. It is less expensive than you think unless you really process lots and lots of these. In your case it probably won't actually copy anything, and the compiler will secretly move the copy it made anyway.
You can also take a non-const reference to a string and "swap" it in
With C++11 there is a further option of using move semantics, which means the string passed in will become "acquired", itself invalidated. This is particularly useful when you do want to take in temporaries, which yours is an example of (although mostly temporaries are constructed through an explicit constructor or a return value).
The problem is that in this code:
Foo foo1("Hey");
From the string literal "Hey" (raw char array, more precisely const char [4], considering the three characters in Hey and the terminating \0) a temporary std::string instance is created, and it is passed to the Foo(const string&) constructor.
This constructor saves a reference to this temporary string into the const string& _bar data member:
Foo(const string& bar)
: _bar(bar) { }
Now, the problem is that you are saving a reference to a temporary string. So when the temporary string "evaporates" (after the constructor call statement), the reference becomes dangling, i.e. it references ("points to...") some garbage.
So, you incur in undefined behavior (for example, compiling your code using MinGW on Windows with g++, I have a different result).
Instead, in this second case:
string barString = "You";
Foo foo2(barString);
your foo2::_bar reference is associated to ("points to") the barString, which is not temporary, but is a local variable in main(). So, after the constructor call, the barString is still there when you print the string using cout << foo2.GetBar().
Of course, to fix that, you should consider using a std::string data member, instead of a reference.
In this way, the string will be deep-copied into the data member, and it will persist even if the input source string used in the constructor is a temporary (and "evaporates" after the constructor call).
Only for curiosity and educating and clarification reasons I would like to ask that the way I use references and values are good practices or not.
Theoretically:
class ComplexGraphicalShape {
...
public:
void setRasterImageURL(const QString &rasterImageURL);
const QString &rasterImageURL() const;
...
private:
const QString *_rasterImageURL;
};
...
void ShadowGram::setRasterImageURL(const QString &rasterImageURL) {
safeDelete(_rasterImageURL); // handle deletion
_rasterImageURL = new QString(rasterImageURL);
}
const QString &ShadowGram::rasterImageURL() const{
// Question 2: Why is it a problem if I return
// return "www.url.com/shape_url.jpg"
return *_rasterImageURL; // that is the right way
}
...
complexGraphicalShape().setRasterImageURL(kURLImagesToShare + imageName);
complexGraphicalShape().setRasterImageURL("www.url.com/url.jpg"); // Question 1.
My first question is that how long can I use the temporary object reference which is created inside setRasterImageURL functioncall? Where exist that variable?(in the stack If I am not mistaken, but what if I call another function with that temporary reference.
My second question is that why I got a warning in Question 2 section if I would like to use this return "www.url.com/shape_url.jpg"? That thing is kind of similar. How long can I use that temporary object?
Thanks for your time for the answer and explanations
The temporary exists until setRasterImageURL returns, so you can safely pass a reference to it along, but you need to be careful not to save the reference for later. The temporary is stored wherever the compiler wants to. The reference is most likely passed either in a register or on the stack.
It is a problem because you're returning a reference to a temporary QString object, and that object is destroyed when the function returns. You're not allowed to use the reference at all.
Passing a reference "inwards" to a function is (usually) safe as long as you don't store it, while passing a reference "outwards" from a function requires you to make sure that the referenced object still exists when the function returns.
Q1: The temporary string exists as long as the temporary reference that is "bound" to it. That is - as long as you are "inside" setRasterImageURL() function. This - of course - includes all functions called "within" this function. Note that storing another reference to this temporary string does NOT prolong the lifetime of the temporary object.
complexGraphicalShape().setRasterImageURL("www.url.com/url.jpg");
// the temporary object is "destroyed" when it goes out of scope, and it's scope is just the called function
Q2: The problem with returning is that you use "C string" (array of characters) to create a temporary QString object (on stack, still inside the function) and return reference to that temporary. As this temporary object is destroyed right after this function returns, your reference is never valid and refers to a dead object. On the other hand - returning a reference to a member variable works, because this object is not destroyed, so the reference is valid as long as your main object lives.
const QString &ShadowGram::rasterImageURL() const{
return "www.url.com/shape_url.jpg"
// the temporary object is destroyed here, before the function returns, reference is invalid
}
My first question is that how long can I use the temporary object reference which is created inside setRasterImageURL functioncall?
It's not created inside the function call, it's created on the caller's stack before the function is called, and is destroyed after the function returns.
Where exist that variable?(in the stack If I am not mistaken, but what if I call another function with that temporary reference.
Yes, on the stack. It is destroyed at the ; after the function call returns (at the end of the "full expression").
That thing is kind of similar. How long can I use that temporary object?
Until the end of the full expression that creates the temporary, which is the return statement, so it goes out of scope immediately before the function has even finished returning. That's why you get a warning - the returned reference is bound to an object which no longer exists, and is never safe to use.
Both these cases are covered by 12.2 [class.temporary] paragraph 5 in the standard:
— A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
— The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
//old school '98 c++, no C++0x stuff
std::string getPath();
void doSomething()
{
const std::string &path = getPath(); //const reference to an rvalue
... // doSomething with path
}
void doSomething2()
{
const std::string path = getPath(); //regular variable
... // doSomething with path
}
what are the differences between doSomething and doSomething2 and which one is prefferable?
Is it safe to use const reference to returned rvalue in doSomething?
Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?
Is it safe to use const reference to returned rvalue in doSomething?
Yes, this is perfectly fine. The language has an specific clause that guarantees that if you bind a reference to an rvalue a temporary is created and the lifetime is extended until the end of the scope where the reference is created.
Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?
In both cases the cost is the same, as the compiler will do RVO (return value optimization)
what are the differences between doSomething and doSomething2 and which one is prefferable?
The main difference is that in one case you are giving a name to the real object and in the other case the name is given to a reference. The compiler should generate exactly the same code in both versions.
That being said, I find the use of the const& to be misleading. It gives the impression that the local function has a reference to some object somewhere, but it really has a copy (with no name). To realize that this is a copy the maintainer will have to look and verify the signature of the function that is being called. In the case of the value the behavior is more obvious: the function maintains a copy of whatever is returned by the function (which might be a value or reference).
The second difference is that you are only legally allowed to bind a const reference, which means that the function cannot modify the object. In the case of storing a value, the type can be non-const and the function could modify that object, so the approach is more flexible.
In C++03 the only reason to use the const& trick is in the case where you know that the function returns a value, you know that the type derives from a well known base, and you don't want to name the type [Take a look at ScopeGuard]. In C++11 that use is no longer important, as you can just use auto to let the compiler figure out the type automatically.
(from other comments it seems this might be C++ standards version dependant as to guarentees when you bind a reference to an rvalue about its lifespan - this answer reflects C++ classic)
doSomething has a reference to what?
doSomething2 has a copy of something that may not exists anymore which is fine
lets look at getPath():
in general it will take the return value, copy it to the stack and then copy that to the lhs
it can just assign directly to the lhs
it can return "hello" which will create a string on the stack - this cannot be referenced because it is temporary (the problem with doSomething)
it can return a static const string - in which case it can be completely inlined and assigned to the lhs
The reference version could have a dangling reference if the std::string was allocated inside the function getPath() and destroyed when returning from that function.
Then, it's dangerous usage.
If you had a class holding that string and the class outlives the scope of that const std::string & reference, something as MyClass::getPath(), then, in that case, the reference wouldn't be dangling.
The second version will always work.