When I pass an object to another object as a const reference, is there a copy made? I always assumed since I passed in the object by reference the member object itself was actually the object I passed in and not a copy. I made a test program that causes the passed in reference object to be destroyed at the end of scope, but it doesn't crash as I expected. Is this a bug waiting to happen or is the object getting copied?
#include <iostream>
#include <string>
class Something
{
public:
Something(const std::string& str) : mStr(str) {}
const std::string& str() const
{
return mStr;
}
private:
std::string mStr;
};
int main()
{
Something* something;
{
std::string temp = "Testing.";
something = new Something(temp);
}
std::cout<<something->str()<<"\n";
delete something;
return 0;
}
Is that std::string still valid or is it deleted? (In the object itself)
The data member mStr is of type std::string (it's an object, not a reference).
Therefore, when you initialize it in the constructor's initialization list (via : mStr(str)), the argument, which was passed by reference, is copied. In your example, only the initialization causes a copy to be made: if you removed the initialization, no copies would be made.
Contents of temp variable is copied to mStr. The code is valid.
You are correct, except you are missing the fact that mStr(str) makes a copy of str. This copy is destroyed in ~Somthing();
Related
Take the following snippet of code
#include <iostream>
#include <string>
class Foo {
private:
std::string m_name;
public:
Foo(std::string name) : m_name { name } {}
const std::string & get_name() const { return m_name; }
};
int main() {
Foo x { "bob" };
x.get_name();
}
Because I initialized an object and name exists somewhere in memory, is a temporary object is made when I call the x.get_name()? If a temporary object is made, than is there a point to returning by reference? My understanding is you return by reference so to avoid the cost of creating a large object or when using an std::ostream& object because you have to.
Yes, there is a point, you return by reference if you want to return a reference to some object.
Why would you want to have a reference to some object? Exactly because you need to access it and not a copy of it. Reasons might vary, basic ones are that you do not want to make an extra copy - e.g. the get_name you posted, maybe you want to store it and access it later, and/or because you want to modify it.
Returning a reference is not much different from a passing parameter by reference.
No temporary std::string object is made in x.get_name(). The method returns lvalue reference by value. Since references are usually implemented as pointers, the true return value is a pointer. So a copy of the pointer is made during each call but that is like returning an int - can be done in registers or stack. So it's as cheap as it gets.
Yes, your understanding is correct, although I would say that const T& is used when we want to avoid copy for whatever reasons and T& should only be used when we need to get mutable access to the object - e.g. std::ostream& in operator<< which mutates the stream by printing into it.
BTW, you make an extra copy in your ctor - name parameter is copied into name member. Instead you should move it there like Foo(std::string name):name(std::move(name)){}.
#include <iostream>
#include <string>
using namespace std;
class Wrapper
{
public:
std::string&& get() &&
{
std::cout << "rvalue" << std::endl;
return std::move(str);
}
const std::string& get() const &
{
std::cout << "lvalue" << std::endl;
return str;
}
private:
std::string str;
};
std::string foo()
{
Wrapper wrap;
return wrap.get();
}
std::string bar()
{
Wrapper wrap;
return std::move(wrap.get());
}
std::string fooRvalue()
{
return Wrapper().get();
}
std::string barRvalue()
{
return std::move(Wrapper().get());
}
int main() {
while(1)
{
std::string s = foo();
std::string s2 = bar();
std::string s3 = fooRvalue();
std::string s4 = barRvalue();
}
return 0;
}
Is the return value of const std::string&, and std::string&& safe in this use case (pretend std::string is some other type that may be not copyable). I thought it would not work because the refernce should point to some local variable which would go out of scope, but it appears to work just fine? Also i've seen the && syntax used before, did i use it correctly (i restricted it to when Wrapper is itself an rvalue).
Im just a little generally confused when returning a reference is safe, i thought the rule was that the object had to outlive the value being returned but i've seen things like the standard library and boost returing reference before. If i store the reference they give me in a variable (that is not a reference) it all seems to work just fine if i then return that stored variable. Can someone fix me up, and give me some good rules to follow.
Here's the ideone i was playing around with, it all seems to work: http://ideone.com/GyWQF6
Yes, this is a correct and safe way of implementing a member getter. But you could make one improvement, which I'll get to. The key is that the lifetime of the std::string member is (almost) the same as the lifetime of the Wrapper object which contains it. And a temporary is only destroyed at the end of the full-expression where it appears, not immediately after it's "used". So in return std::move(Wrapper().get());, the Wrapper is created, get() is called, std::move is called, the return value is constructed, and only then the Wrapper and its string are destroyed.
The only danger is if somebody binds another reference to your member. But that would be their mistake, and ordinary const-reference getters have the same danger. This is the equivalent of the incorrect const char* ptr = "oops"s.c_str();.
std::string foo()
{
Wrapper wrap;
return wrap.get();
}
foo copy constructs the return value from the member. Hopefully that's not a surprise.
std::string bar()
{
Wrapper wrap;
return std::move(wrap.get());
}
bar also copy constructs the return value from the member. What's going on here is that since wrap is an lvalue, the lvalue get() is called, which returns a const lvalue. (Informally, "const std::string&".) Then move converts that to an xvalue, but it's still const. (Informally, "const std::string&&".) The move constructor string(string&&) cannot match here, since the argument is const. But the copy constructor string(const string&) can match, and is called.
If you expected bar to move construct the return value, you may want to add a third overload for non-const lvalues:
std::string& get() & { return str; }
(If you didn't want to allow modifying the member, note that you already sort of did. For example, somebody could do std::move(wrap).get() = "something";.)
Also, if you had return std::move(wrap).get(); instead, that would have move constructed the return value even without the third overload.
std::string fooRvalue()
{
return Wrapper().get();
}
fooRvalue move constructs the return value, since the rvalue get() is used. As already mentioned, the Wrapper lives long enough for this construction to be safe.
std::string barRvalue()
{
return std::move(Wrapper().get());
}
In barRvalue, the move call is absolutely useless. The expression Wrapper().get() is already an xvalue, so move just converts an xvalue of type std::string to ... an xvalue of type std::string. Still just as safe, though.
The return value object of a function will be initialized before the destruction of local variables and temporaries created in the return expression. As such, it is perfectly legitimate to move from locals/temporaries into function return values.
Those four global functions work because they return objects, not references to objects. And that object gets constructed before any of the locals that their constructor parameter reference are destroyed.
barRvalue is rather redundant (since the result of Wrapper().get() is already an rvalue reference), but functional.
Im just a little generally confused when returning a reference is safe
A function returning a reference to an object that has been destroyed is what is unsafe. Returning a reference to a local object, or part of a local object, is unsafe.
Returning a reference to *this or some part of *this is safe, because the this object will outlive the function that returns the reference. It's no different from returning a reference to a parameter that you take by pointer/reference. The object will outlive the function call that returns the reference.
for method:
Object test(){
Object str("123");
return str;
}
then, I had two methods to call it:
code 1:
const Object &object=test();
code 2:
Object object=test();
which one is better? is twice calls to copy constructor happen in code 2 if without optimize?
other what's the difference?
for code2 I suppose:
Object tmp=test();
Object object=tmp;
for code1 I suppose:
Object tmp=test();
Object &object=tmp;
but the tmp will be deconstructor after the method.so it must add const?
is code 1 right without any issues?
Let's analyse your function:
Object test()
{
Object temp("123");
return temp;
}
Here you're constructing a local variable named temp and returning it from the function. The return type of test() is Object meaning you're returning by value. Returning local variables by value is a good thing because it allows a special optimization technique called Return Value Optimization (RVO) to take place. What happens is that instead of invoking a call to the copy or move constructor, the compiler will elide that call and directly construct the initializer into the address of the caller. In this case, because temp has a name (is an lvalue), we call it N(amed)RVO.
Assuming optimizations take place, no copy or move has been performed yet. This is how you would call the function from main:
int main()
{
Object obj = test();
}
That first line in main seems to be of particular concern to you because you believe that the temporary will be destroyed by the end of the full expression. I'm assuming it is a cause for concern because you believe obj will not be assigned to a valid object and that initializing it with a reference to const is a way to keep it alive.
You are right about two things:
The temporary will be destroyed at the end of the full expression
Initializing it with a reference to const will extend its life time
But the fact that the temporary will be destroyed is not a cause for concern. Because the initializer is an rvalue, its contents can be moved from.
Object obj = test(); // move is allowed here
Factoring in copy-elision, the compiler will elide the call to the copy or move constructor. Therefore, obj will be initialized "as if" the copy or move constructor was called. So because of these compiler optimizations, we have very little reason to fear multiple copies.
But what if we entertain your other examples? What if instead we had qualified obj as:
Object const& obj = test();
test() returns a prvalue of type Object. This prvalue would normally be destructed at the end of the full expression in which it is contained, but because it is being initialized to a reference to const, its lifetime is extended to that of the reference.
What are the differences between this example and the previous one?:
You cannot modify the state of obj
It inhibits move semantics
The first bullet point is obvious but not the second if you are unfamiliar with move semantics. Because obj is a reference to const, it cannot be moved from and the compiler cannot take advantage of useful optimizations. Assigning reference to const to an rvalue is only helpful in a narrow set of circumstances (as DaBrain has pointed out). It is instead preferable that you exercise value-semantics and create value-typed objects when it makes sense.
Moreover, you don't even need the function test(), you can simply create the object:
Object obj("123");
but if you do need test(), you can take advantage of type deduction and use auto:
auto obj = test();
Your last example deals with an lvalue-reference:
[..] but the tmp will be destructed after the method. So must we add const?
Object &object = tmp;
The destructor of tmp is not called after the method. Taking in to account what I said above, the temporary to which tmp is being initialized will be moved into tmp (or it will be elided). tmp itself doesn't destruct until it goes out of scope. So no, there is no need to use const.
But a reference is good if you want to refer to tmp through some other variable. Otherwise, if you know you will not need tmp afterwards, you can move from it:
Object object = std::move(tmp);
Both your examples are valid - in 1 const reference refers to a temporary object, but lifetime of this object is prolonged till the reference goes out of scope (see http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/). The second example is obviously valid, and most modern compilers will optimize away additional copying (even better if you use C+11 move semantics) so for practical purposes examples are equivalent (though in 2 additionally you can modify the value).
In C++11, std::string has a move constructor / move assignment operator, hence the code:
string str = test();
will (at worst) have one constructor call and one move assignment call.
Even without move semantics, this will (likely) be optimised away by NRVO (return value optimisation).
Don't be afraid of returning by value, basically.
Edit: Just to make it 100% clear what is going on:
#include <iostream>
#include <string>
class object
{
std::string s;
public:
object(const char* c)
: s(c)
{
std::cout << "Constructor\n";
}
~object()
{
std::cout << "Destructor\n";
}
object(const object& rhs)
: s(rhs.s)
{
std::cout << "Copy Constructor\n";
}
object& operator=(const object& rhs)
{
std::cout << "Copy Assignment\n";
s = rhs.s;
return *this;
}
object& operator=(object&& rhs)
{
std::cout << "Move Assignment\n";
s = std::move(rhs.s);
return *this;
}
object(object&& rhs)
: s(std::move(rhs.s))
{
std::cout << "Move Constructor\n";
}
};
object test()
{
object o("123");
return o;
}
int main()
{
object o = test();
//const object& o = test();
}
You can see that there is 1 constructor call and 1 destructor call for each - NRVO kicks in here (as expected) eliding the copy/move.
Code 1 is correct. As I said, the C++ Standard guarantees a temporary to a const reference is valid. It's main usage is polymorphic behavior with refenences:
#include <iostream>
class Base { public: virtual void Do() const { std::cout << "Base"; } };
class Derived : public Base { public: virtual void Do() const { std::cout << "Derived"; } };
Derived Factory() { return Derived(); }
int main(int argc, char **argv)
{
const Base &ref = Factory();
ref.Do();
return 0;
}
This will return "Derived". A famouse example was Andrei Alexandrescu's ScopeGuard but with C++11 it's even simpler yet.
Does C++ provide a guarantee for the lifetime of a temporary variable that is created within a function call but not used as a parameter? Here's an example class:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
And here's how you would use it:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
When will the destructor for the temporary StringBuffer object get called? Is it:
Before the call to GetString?
After GetString returns?
Compiler dependent?
I know that C++ guarantees that a local temporary variable will be valid as long as there's a reference to it - does this apply to parent objects when there's a reference to a member variable?
Thanks.
The destructor for that sort of temporaries is called at the end of the full-expression. That's the most outer expression which is not part of any other expression. That is in your case after the function returns and the value is evaluated. So, it will work all nice.
It's in fact what makes expression templates work: They can keep hold references to that sort of temporaries in an expression like
e = a + b * c / d
Because every temporary will last until the expression
x = y
Is evaluated completely. It's quite concisely described in 12.2 Temporary objects in the Standard.
litb's answer is accurate. The lifetime of the temporary object (also known as an rvalue) is tied to the expression and the destructor for the temporary object is called at the end of the full expression and when the destructor on StringBuffer is called, the destructor on m_buffer will also be called, but not the destructor on m_str since it is a reference.
Note that C++0x changes things just a little bit because it adds rvalue references and move semantics. Essentially by using an rvalue reference parameter (notated with &&) I can 'move' the rvalue into the function (instead of copying it) and the lifetime of the rvalue can be bound to the object it moves into, not the expression. There is a really good blog post from the MSVC team on that walks through this in great detail and I encourage folks to read it.
The pedagogical example for moving rvalue's is temporary strings and I'll show assignment in a constructor. If I have a class MyType that contains a string member variable, it can be initialized with an rvalue in the constructor like so:
class MyType{
const std::string m_name;
public:
MyType(const std::string&& name):m_name(name){};
}
This is nice because when I declare an instance of this class with a temporary object:
void foo(){
MyType instance("hello");
}
what happens is that we avoid copying and destroying the temporary object and "hello" is placed directly inside the owning class instance's member variable. If the object is heavier weight than a 'string' then the extra copy and destructor call can be significant.
After the call to GetString returns.
I wrote almost exactly the same class:
template <class C>
class _StringBuffer
{
typename std::basic_string<C> &m_str;
typename std::vector<C> m_buffer;
public:
_StringBuffer(std::basic_string<C> &str, size_t nSize)
: m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; }
~_StringBuffer()
{ commit(); }
C *get()
{ return &(m_buffer[0]); }
operator C *()
{ return get(); }
void commit()
{
if (m_buffer.size() != 0)
{
size_t l = std::char_traits<C>::length(get());
m_str.assign(get(), l);
m_buffer.resize(0);
}
}
void abort()
{ m_buffer.resize(0); }
};
template <class C>
inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize)
{ return _StringBuffer<C>(str, nSize); }
Prior to the standard each compiler did it differently. I believe the old Annotated Reference Manual for C++ specified that temporaries should clean up at the end of the scope, so some compilers did that. As late as 2003, I found that behaviour still existed by default on Sun's Forte C++ compiler, so StringBuffer didn't work. But I'd be astonished if any current compiler was still that broken.
StringBuffer is in the scope of GetString. It should get destroyed at the end of GetString's scope (ie when it returns). Also, I don't believe that C++ will guarantees that a variable will exist as long as there is reference.
The following ought to compile:
Object* obj = new Object;
Object& ref = &(*obj);
delete obj;
From cppreference:
All temporary objects are destroyed as the last step in evaluating the
full-expression that (lexically) contains the point where they were
created, and if multiple temporary objects were created, they are
destroyed in the order opposite to the order of creation. This is true
even if that evaluation ends in throwing an exception.
Does C++ provide a guarantee for the lifetime of a temporary variable that is created within a function call but not used as a parameter? Here's an example class:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
And here's how you would use it:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
When will the destructor for the temporary StringBuffer object get called? Is it:
Before the call to GetString?
After GetString returns?
Compiler dependent?
I know that C++ guarantees that a local temporary variable will be valid as long as there's a reference to it - does this apply to parent objects when there's a reference to a member variable?
Thanks.
The destructor for that sort of temporaries is called at the end of the full-expression. That's the most outer expression which is not part of any other expression. That is in your case after the function returns and the value is evaluated. So, it will work all nice.
It's in fact what makes expression templates work: They can keep hold references to that sort of temporaries in an expression like
e = a + b * c / d
Because every temporary will last until the expression
x = y
Is evaluated completely. It's quite concisely described in 12.2 Temporary objects in the Standard.
litb's answer is accurate. The lifetime of the temporary object (also known as an rvalue) is tied to the expression and the destructor for the temporary object is called at the end of the full expression and when the destructor on StringBuffer is called, the destructor on m_buffer will also be called, but not the destructor on m_str since it is a reference.
Note that C++0x changes things just a little bit because it adds rvalue references and move semantics. Essentially by using an rvalue reference parameter (notated with &&) I can 'move' the rvalue into the function (instead of copying it) and the lifetime of the rvalue can be bound to the object it moves into, not the expression. There is a really good blog post from the MSVC team on that walks through this in great detail and I encourage folks to read it.
The pedagogical example for moving rvalue's is temporary strings and I'll show assignment in a constructor. If I have a class MyType that contains a string member variable, it can be initialized with an rvalue in the constructor like so:
class MyType{
const std::string m_name;
public:
MyType(const std::string&& name):m_name(name){};
}
This is nice because when I declare an instance of this class with a temporary object:
void foo(){
MyType instance("hello");
}
what happens is that we avoid copying and destroying the temporary object and "hello" is placed directly inside the owning class instance's member variable. If the object is heavier weight than a 'string' then the extra copy and destructor call can be significant.
After the call to GetString returns.
I wrote almost exactly the same class:
template <class C>
class _StringBuffer
{
typename std::basic_string<C> &m_str;
typename std::vector<C> m_buffer;
public:
_StringBuffer(std::basic_string<C> &str, size_t nSize)
: m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; }
~_StringBuffer()
{ commit(); }
C *get()
{ return &(m_buffer[0]); }
operator C *()
{ return get(); }
void commit()
{
if (m_buffer.size() != 0)
{
size_t l = std::char_traits<C>::length(get());
m_str.assign(get(), l);
m_buffer.resize(0);
}
}
void abort()
{ m_buffer.resize(0); }
};
template <class C>
inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize)
{ return _StringBuffer<C>(str, nSize); }
Prior to the standard each compiler did it differently. I believe the old Annotated Reference Manual for C++ specified that temporaries should clean up at the end of the scope, so some compilers did that. As late as 2003, I found that behaviour still existed by default on Sun's Forte C++ compiler, so StringBuffer didn't work. But I'd be astonished if any current compiler was still that broken.
StringBuffer is in the scope of GetString. It should get destroyed at the end of GetString's scope (ie when it returns). Also, I don't believe that C++ will guarantees that a variable will exist as long as there is reference.
The following ought to compile:
Object* obj = new Object;
Object& ref = &(*obj);
delete obj;
From cppreference:
All temporary objects are destroyed as the last step in evaluating the
full-expression that (lexically) contains the point where they were
created, and if multiple temporary objects were created, they are
destroyed in the order opposite to the order of creation. This is true
even if that evaluation ends in throwing an exception.