3

For example I have a class that call a function in its consturctor that returns local object. I'm trying to use rvalue references to get access to this object to avoid expensive move of it in memory.

   class MyClass
    {
        BigObject&& C;
        MyClass() : C(f())
        {
        };
    };
   BigObject f()
   {
       return BigObject();
   }

But compiller tells me that reference member is initialized to a temporary that doesn't persist after the construction exits.

I don't get it. I understand that local objects, created in a scope of a function, exists only in a scope of function. Reaching the end of the scope - destructors of local objects are called. And here I initialize rvalue reference with local object , and I have access to it, while I'm in the body of constuctor.

Can someone explain, what is going on here? And is there a way to return a local object and use it as any ligetable class member, without moving it in memory?

Il'ya Zhenin
  • 1,272
  • 2
  • 20
  • 31
  • 1
    "while I'm in the body of constuctor" `C(f())` is not in `c'tor` body. Its in initialization list. – sameerkn May 30 '16 at 08:44
  • 1
    What do you want your reference to refer to? Who will own the memory and how will the owner dispose of it? – n. m. could be an AI May 30 '16 at 08:45
  • @sameerkn, and? I wrote that I have access to this object in the constructor body. Obviously, I initialize this in initialization list. – Il'ya Zhenin May 30 '16 at 08:48
  • @n.m.to object, that was created in function f(). That class has its own destructor, that will free memory. Actually, It can be more complicated than that, but do you need these details to answer question? If so, I do not understad why, so asking there for little theory filling :) – Il'ya Zhenin May 30 '16 at 08:50
  • The memory used to store the object is only allocated for the length of the function. Unless you put the object in dynamic or static memory. Therefore it has to be moved out. – user1937198 May 30 '16 at 08:53
  • The result of `f()` is a temporary object, as the compiler says. It is destroyed immediately after `C` has been initialised (that is, before entering the constructor's body). – molbdnilo May 30 '16 at 08:59
  • "to object, that was created in function f()." That object ceases to exist when the function returns. You have a chance to copy it before it disappears. "destructor, that will free memory". Destructors don't free memory of objects they destroy. "do you need these details to answer question?" No, these are *rhetorical* questions. I ask them because i want *you* to think about them. – n. m. could be an AI May 30 '16 at 09:16

2 Answers2

5

You should remove the && from C.

The code is not as expensive as you imagine: f's return value is a copy elision context. So the compiler is allowed to construct just a single BigObject directly in the memory space for C. Even if a compiler doesn't perform this , it is still a move context so as worst case scenario the object will be moved.

If somehow your object is copyable but not movable then you do have to rely on copy elision but it's hard to imagine a valid use case for such an object.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
1

To quote it from the standard,

Section 12.2.5
The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except: — A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.

So, in your case 'C(f())', C gets bound to the temporary only till the constructor exits and after that it's kind of UB and is upto your luck. You should be thankful that the compiler reported a warning :).

Anyhow, there is no need to do such acrobatics, but you can always move from the temporary into 'C'.

class BigObject
{
public:
  BigObject() {std::cout << "Cons" << std::endl;}
  BigObject(const BigObject& other) {std::cout << "Copy Cons" << std::endl;}
  BigObject(BigObject&& other) {std::cout << "Move Cons" << std::endl;}
};

BigObject f()
{
  return BigObject();
}

class MyClass
{
public:
  BigObject C;

  MyClass() : C(f())
  {
  };

};

In this case compiler can very well elide the copy making the code as efficient as possible by just having to construct 'BigObject' once at the target site.

So, in this particular case it could be possible that your object is not moved at all or even copied. Perhaps that answers your final question.

Arunmu
  • 6,837
  • 1
  • 24
  • 46