Reputation: 1123
I'd like to create an object using a
object().addSomething().addSomethingElse()
syntax and then use it in a part of the code, but the following code won't work:
class myObj {
public:
myObj() {}
~myObj() { std::cout << "dtor called" << std::endl; }
myObj& someOtherOperation() {
return *this;
}
};
int main() {
auto& elementRef = myObj().someOtherOperation();
{
std::cout << "some stuff that uses elementRef" << std::endl;
}
}
the destructor is called before the part of the code that uses the reference.
I would like to avoid an expensive object copy operation and keeping the
object().addSomething().addSomethingElse()
syntax, but it seems references don't allow for that. Any solutions to this?
Upvotes: 3
Views: 80
Reputation: 114579
You can get a life "extension" if you return an object and bind it to a reference, i.e.
const Obj& foo = func_returning_an_instance();
in this case the instance is guaranteed to live as long as the reference.
If however your method is returning a reference no extension of the bound object is done... therefore in
const Obj& r = Obj().ref_retuning_method().ref_returning_method();
the expression will be computed correctly (i.e. the Obj
instance will live enough for the full expression to be computed, thus allowing the reference returned by first call to be valid for a second call too), but the object will cease its life right after the reference r
initialization and it won't be legal to use r
after it.
Upvotes: 1
Reputation: 9002
Create the object independently:
auto o = myObj();
and then use it freely:
o.someOtherOperation().someOtherOperation();
Upvotes: 6
Reputation:
Yes, there is a special exception that allows the lifetime of temporaries to be extended if they're bound to references, but when that binding is hidden through a function, it doesn't and cannot work. int main()
could be defined in an entirely separate translation unit, where it wouldn't even see the body of someOtherOperation()
.
You should only return *this
by reference when you've got an lvalue.
myObj& someOtherOperation() & {
// -------------------------^--
...
return *this;
}
You can return by value, by moving from *this
, when your method is called on an rvalue:
myObj someOtherOperation() && {
// ------------------------^^--
someOtherOperation(); // keep implementation in other overload
return std::move(*this);
}
Upvotes: 1
Reputation: 65770
You can optimize by using move semantics when the implicit object parameter is an rvalue:
myObj someOtherOperation() & {
return *this;
}
myObj someOtherOperation() && {
return std::move(*this);
}
An example of the difference:
auto element = myObj().someOtherOperation(); //uses move semantics
myobj obj;
auto otherElement = obj.someOtherOperation(); //doesn't use move semantics
Upvotes: 1