延长变量的生命周期
Expanding the lifetime of a variable
#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;
}
我知道这行得通。但我的观点是,这个“5.5”右值是否会直接转移到相同但动态分配的地址?也就是说,即使 temp
不再在范围内,ptr
是否仍然指向 temp
?
假设这是一个巨大的数组,我们希望从短期本地范围移动到长期存储,稍后我们决定变量何时消亡。
更多解释:
假设我们在内存中有地址A。它会在一段时间内死亡,但在它死亡之前我们正在做一个很酷的技巧并锁定这个相同的 A 地址,这样它就不会死亡。因此我们不必复制东西来保持它的活力。我们只是锁定了它。这在 C++ 中可能吗?
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
或内置数组类型,您应该复制您的值(不能移动)。
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object.
In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.
那么什么是 xvalue,rvalue ...?
来自C++ reference - value_category
The programming language CPL was first to introduce value categories for expressions: all CPL expressions can be evaluated in "right-hand mode", but only certain kinds of expression are meaningful in "left-hand mode". When evaluated in right-hand mode, an expression is regarded as being a rule for the computation of a value (the right-hand value, or rvalue). When evaluated in left-hand mode an expression effectively gives an address (the left-hand value, or lvalue). "Left" and "Right" here stood for "left of assignment" and "right of assignment".
C++11
With the introduction of move semantics in C++11, value categories were redefined to characterize two independent properties of expressions[5]:
has identity: it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly);
can be moved from: move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression.
In C++11, expressions that:
- have identity and cannot be moved from are called lvalue expressions;
- have identity and can be moved from are called xvalue expressions;
- do not have identity and can be moved from are called prvalue ("pure rvalue") expressions;
- do not have identity and cannot be moved from are not used[6].
The expressions that have identity are called "glvalue expressions" (glvalue stands for "generalized lvalue"). Both lvalues and xvalues are glvalue expressions.
The expressions that can be moved from are called "rvalue expressions". Both prvalues and xvalues are rvalue expressions.
- temp (double) 具有“身份”。
- temp (double) 不能“从中移动”,
因为它缺少“移动构造函数、移动赋值运算符或其他实现移动语义的函数重载”
所以只有该值将用于构造新变量。
#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;
}
我知道这行得通。但我的观点是,这个“5.5”右值是否会直接转移到相同但动态分配的地址?也就是说,即使 temp
不再在范围内,ptr
是否仍然指向 temp
?
假设这是一个巨大的数组,我们希望从短期本地范围移动到长期存储,稍后我们决定变量何时消亡。
更多解释:
假设我们在内存中有地址A。它会在一段时间内死亡,但在它死亡之前我们正在做一个很酷的技巧并锁定这个相同的 A 地址,这样它就不会死亡。因此我们不必复制东西来保持它的活力。我们只是锁定了它。这在 C++ 中可能吗?
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
或内置数组类型,您应该复制您的值(不能移动)。
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object.
In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.
那么什么是 xvalue,rvalue ...?
来自C++ reference - value_category
The programming language CPL was first to introduce value categories for expressions: all CPL expressions can be evaluated in "right-hand mode", but only certain kinds of expression are meaningful in "left-hand mode". When evaluated in right-hand mode, an expression is regarded as being a rule for the computation of a value (the right-hand value, or rvalue). When evaluated in left-hand mode an expression effectively gives an address (the left-hand value, or lvalue). "Left" and "Right" here stood for "left of assignment" and "right of assignment".
C++11
With the introduction of move semantics in C++11, value categories were redefined to characterize two independent properties of expressions[5]:
has identity: it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly);
can be moved from: move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression.
In C++11, expressions that:
- have identity and cannot be moved from are called lvalue expressions;
- have identity and can be moved from are called xvalue expressions;
- do not have identity and can be moved from are called prvalue ("pure rvalue") expressions;
- do not have identity and cannot be moved from are not used[6].
The expressions that have identity are called "glvalue expressions" (glvalue stands for "generalized lvalue"). Both lvalues and xvalues are glvalue expressions.
The expressions that can be moved from are called "rvalue expressions". Both prvalues and xvalues are rvalue expressions.
- temp (double) 具有“身份”。
- temp (double) 不能“从中移动”,
因为它缺少“移动构造函数、移动赋值运算符或其他实现移动语义的函数重载”
所以只有该值将用于构造新变量。