如何在函数中使用本地创建的对象而不将其复制到内存中?

时间:2016-05-30 08:37:07

标签: c++ class memory rvalue-reference rvalue

例如,我有一个类在其consturctor中调用一个返回本地对象的函数。我正在尝试使用rvalue引用来访问此对象,以避免在内存中进行昂贵的移动。

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

但是compiller告诉我,引用成员被初始化为一个在构造退出后不会持久的临时成员。

我不明白。我理解在函数范围内创建的本地对象仅存在于函数范围内。到达范围的末尾 - 调用本地对象的析构函数。在这里,我使用本地对象初始化rvalue引用,并且我可以访问它,而我在constuctor的主体中。

有人可以解释一下,这里发生了什么?有没有办法返回一个本地对象并将其用作任何ligetable类成员,而不将其移动到内存中?

2 个答案:

答案 0 :(得分:5)

您应该从&&删除C

代码并不像您想象的那么昂贵:f的返回值是copy elision上下文。因此,允许编译器直接在BigObject的内存空间中构造单个C。即使编译器没有执行此操作,它仍然是一个移动上下文,因此在最坏的情况下,对象将被移动。

如果你的对象是可复制但不可移动的,那么你必须依赖复制省略,但很难想象这个对象的有效用例。

答案 1 :(得分:1)

从标准中引用它,

  

第12.2.5节
第二个上下文是指引用的时间   暂时的。引用绑定的临时或   临时的,是子对象的完整对象   引用的持久性在引用的生命周期中持续存在,除了:    - 临时绑定到构造函数中的引用成员   ctor-initializer(12.6.2)一直存在,直到构造函数退出。

所以,在你的情况下'C(f())',C只被绑定到临时,直到构造函数退出,之后它就是UB并且运气好了。你应该感谢编译器报告了一个警告:)。

无论如何,没有必要做这样的杂技,但你总是可以从临时的'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())
  {
  };

};

在这种情况下,编译器可以很好地删除副本,使代码尽可能高效,只需在目标站点构造一次“BigObject”。

因此,在这种特殊情况下, 可以 可能您的对象根本不会移动或甚至复制。也许这回答了你的最后一个问题。