Albert
Albert

Reputation: 1123

Reference destructing object before use

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

Answers (4)

6502
6502

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

dlask
dlask

Reputation: 9002

Create the object independently:

auto o = myObj();

and then use it freely:

o.someOtherOperation().someOtherOperation();

Upvotes: 6

user743382
user743382

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

TartanLlama
TartanLlama

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

Related Questions