扩展变量的生命周期

时间:2017-03-28 08:24:32

标签: c++ optimization move-semantics dynamic-allocation

#include <iostream>
#include <utility>
int main()
{
    double* ptr;
    {
        double temp = 5.5;
        ptr = new double(std::move(temp));
    }   // temp dies here
    std::cout << *ptr << "\n";
    delete ptr;
}

我知道这很有效。但我的观点是这个&#34; 5.5&#34; rvalue会被直接转移到相同但动态分配的地址吗?也就是说,即使ptr不在范围内,temp仍指向temp吗?

让我们说这是一个巨大的阵列,我们希望从短期本地范围转移到长期存储,之后我们决定变量何时消亡。

更多解释:

假设我们在内存中有地址A.它会在一段时间内死亡,但在它死之前我们正在制作一个很酷的技巧并锁定这个相同的A地址,这样它就不会死掉。因此,我们不必复制东西以保持活着。我们刚刚锁定它。这可能在c ++中吗?

2 个答案:

答案 0 :(得分:2)

C ++不直接支持它。如果对象超出范围,其生命周期结束,并且该对象的任何指针都无效(即取消引用它们会调用未定义的行为)。

然而,这并不是代码中发生的事情:

double* ptr;
{
    double temp = 5.5;
    ptr = new double(std::move(temp));
}   // temp dies here

这里std::move是一个无操作(什么都不做),代码等同于更简单的变体

double* ptr;
{
    double temp = 5.5;
    ptr = new double(temp);
}   // temp dies here

double对象是动态分配的,并使用5.5初始化;这里没什么特别的。

但是如果你有一个巨大的数组而不是一个double对象呢?然后,您可能正在使用std::vectorstd:valarray,并且它们的数据元素始终是动态分配的。然后,在示例中使用std::move是有意义的,它具有正确的行为:

std::vector<double> values;
{
    std::vector<double> temp;
    // fill the temp array
    if (... want to extend life time of temp ...)
    {
        values = std::move(temp);
    }
}   // temp dies here
// now 'values' is either empty or holds the temp values

或者,如果您使用std::array或内置数组类型,则应复制值(无法移动)。

答案 1 :(得分:0)

来自C++ reference - std::move

  

std :: move用于表示对象t可以从&#34;移出,即允许资源从t有效地转移到另一个对象。

     

特别是,std :: move生成一个xvalue表达式,用于标识其参数t。它完全等同于static_cast到rvalue引用类型。

那么什么是xvalue,rvalue ......?

来自C++ reference - value_category

  

编程语言CPL首先引入了表达式的值类别:所有CPL表达式都可以在&#34;右手模式&#34;中进行评估,但只有某些类型的表达式在&#34; left-中有意义手动模式&#34;。在右手模式下评估时,表达式被视为计算值(右手值或右值)的规则。在左手模式下进行评估时,表达式有效地给出了一个地址(左手值或左值)。 &#34;左&#34;和#34;对&#34;这里代表着&#3​​4;任务的左边&#34;和&#34;转让权&#34;。

     

<强> C ++ 11

     

随着C ++ 11中移动语义的引入,重新定义了值类别来表征表达式的两个独立属性[5]:

     

具有标识:可以确定表达式是否与另一个表达式引用相同的实体,例如通过比较对象的地址或它们识别的函数(直接获取或间接地);

     

可以从移动:移动构造函数,移动赋值运算符,或者实现移动语义的另一个函数重载可以绑定到表达式。

     

在C ++ 11中,表达式为:

     
      
  • 具有身份且无法移动被称为左值表达式;
  •   
  • 具有身份并且可以被称为xvalue表达式;
  •   
  • 没有身份且可以被移动称为prvalue(&#34;纯rvalue&#34;)表达式;
  •   
  • 没有身份,不能被移动不被使用[6]。
  •   
     

具有标识的表达式称为&#34; glvalue表达式&#34; (glvalue代表&#34;广义左值&#34;)。 lvalues和xvalues都是glvalue表达式。

     

可以移动的表达式称为&#34; rvalue表达式&#34;。 prvalues和xvalues都是rvalue表达式。

  • temp(double)有&#34; identity&#34;。
  • temp(double)不能&#34;移动&#34;,因为它缺少&#34;移动构造函数,移动赋值运算符或其他实现移动的函数重载语义&#34;

因此,该值将用于构造新变量。