#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 ++中吗?
答案 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::vector
或std: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)
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;这里代表着&#34;任务的左边&#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表达式。
因此,该值将用于构造新变量。