Bas*_*evs 581 c++ c++-faq move-semantics c++11 stdmove
赞赏良好的链接.
Sch*_*ron 249
关于C++ 11 R值参考和移动构造函数的Wikipedia页面
Type &&),则使用移动构造函数而不是复制构造函数.std::move() 是一个转换器,它生成对象的rvalue引用,以便从中移动.这是一种避免复制的新C++方法.例如,使用移动构造函数,std::vector可以将其内部指针复制到新对象,使移动的对象保持不正确状态,从而避免复制所有数据.这将是C++ - 有效.
尝试谷歌搜索移动语义,右值,完美转发.
ein*_*ica 192
虽然std::move() 在技术上是一个功能-我会说这是不是真正的功能.它是编译器考虑表达式值的方式之间的转换器.
首先要注意的是,std::move() 实际上并没有移动任何东西.它将表达式从左值(例如命名变量)转换为x值.xvalue告诉编译器:
你可以掠夺我,移动任何我持有的东西并在其他地方使用它(因为我很快就会被摧毁)".
换句话说,当你使用时std::move(x),你允许编译器蚕食x.因此,如果x在内存中有自己的缓冲区 - 在std::move()编译器之后可以让另一个对象拥有它.
你也可以从一个prvalue(例如你正在传递的临时值)移动,但这很少有用.
提出这个问题的另一种方法是"我会将现有对象的资源用于什么?" 好吧,如果您正在编写应用程序代码,那么您可能不会对编译器创建的临时对象进行大量处理.因此,主要是在构造函数,运算符方法,类似标准库算法等函数的地方执行此操作,其中对象自动创建和销毁很多.当然,这只是一个经验法则.
典型的用法是将资源从一个对象"移动"到另一个对象而不是复制.@Guillaume链接到此页面,其中有一个简单的简短示例:使用较少的复制交换两个对象.
template <class T>
swap(T& a, T& b) {
T tmp(a); // we now have two copies of a
a = b; // we now have two copies of b (+ discarded a copy of a)
b = tmp; // we now have two copies of tmp (+ discarded a copy of b)
}
Run Code Online (Sandbox Code Playgroud)
使用move允许您交换资源而不是复制它们:
template <class T>
swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Run Code Online (Sandbox Code Playgroud)
想想当T是T大小为n 时会发生什么.在第一个版本中,您读取和写入3*n个元素,在第二个版本中,您基本上只读取和写入向量缓冲区的3个指针.当然,T级需要知道如何进行移动; 你应该有一个移动赋值运算符和一个T类的移动构造函数,以便它可以工作.
小智 137
当您需要在其他地方"转移"对象的内容时,可以使用move,而无需复制(例如,内容不重复,这就是为什么它可以用于某些不可复制的对象,如unique_ptr).使用std :: move,对象也可以在不进行复制(并节省大量时间)的情况下获取临时对象的内容.
这个链接真的帮助了我:
http://thbecker.net/articles/rvalue_references/section_01.html
如果我的答案来得太晚,我很抱歉,但我也在寻找std :: move的良好链接,我发现上面的链接有点"严肃".
这强调了r值参考,在哪种情况下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接.
Chr*_*bek 55
std::move?答:std::move()是C++标准库中用于转换为右值引用的函数.
简单地std::move(t)相当于:
static_cast<T&&>(t);
Run Code Online (Sandbox Code Playgroud)
rvalue是一个临时值,它不会超出定义它的表达式,例如从不存储在变量中的中间函数结果.
int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated
Run Code Online (Sandbox Code Playgroud)
在N2027中给出了std :: move()的实现:"Rvalue References简介"如下:
template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
return a;
}
Run Code Online (Sandbox Code Playgroud)
如您所见,无论是使用value(),引用类型()还是rvalue引用()调用,都会std::move返回.T&&TT&T&&
答:作为演员,它在运行时没有做任何事情.只有在编译时才能告诉编译器您希望继续将引用视为右值.
foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)
int a = 3 * 5;
foo(a); // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`
Run Code Online (Sandbox Code Playgroud)
它没有做什么:
答:std::move如果你想调用支持移动语义的函数,你应该使用不是rvalue(临时表达式)的参数.
这为我提出了以下后续问题:
什么是移动语义?与复制语义相比,移动语义是一种编程技术,其中通过"接管"而不是复制另一个对象的成员来初始化对象的成员.这种"接管"只能通过指针和资源句柄来实现,这可以通过复制指针或整数句柄而不是底层数据来便宜地转移.
什么样的类和对象支持移动语义?作为开发人员,您可以在自己的类中实现移动语义,如果这些语言将从传输其成员而不是复制它们中受益.一旦实现了移动语义,您将直接受益于许多库程序员的工作,他们已经添加了对有效处理具有移动语义的类的支持.
为什么编译器不能自己搞清楚?除非你这样说,否则编译器不能只调用函数的另一个重载.您必须帮助编译器选择是否应该调用常规或移动版本的函数.
在哪种情况下,我想告诉编译器它应该将变量视为右值?这很可能发生在模板或库函数中,您知道可以挽救中间结果.
use*_*404 30
std :: move本身并没有做太多.我认为它为一个对象调用了移动的构造函数,但它实际上只执行一个类型转换(将一个左值变量转换为一个右值,以便所述变量可以作为参数传递给移动构造函数或赋值运算符).
因此std :: move仅用作使用移动语义的前兆.移动语义本质上是处理临时对象的有效方式.
考虑对象 A = B + C + D + E + F;
这是漂亮的代码,但E + F产生一个临时对象.然后D + temp产生另一个临时对象,依此类推.在类的每个普通"+"运算符中,都会出现深拷贝.
例如
Object Object::operator+ (const Object& rhs) {
Object temp (*this);
// logic for adding
return temp;
}
Run Code Online (Sandbox Code Playgroud)
在此函数中创建临时对象是无用的 - 当这些临时对象超出范围时,它们将在行尾删除.
我们宁愿使用移动语义来"掠夺"临时对象并执行类似的操作
Object& Object::operator+ (Object&& rhs) {
// logic to modify rhs directly
return rhs;
}
Run Code Online (Sandbox Code Playgroud)
这避免了不必要的深拷贝.参考该示例,发生深度复制的唯一部分现在是E + F.其余部分使用移动语义.还需要实现移动构造函数或赋值运算符以将结果分配给A.
“它是什么?” 和 “它是做什么的?” 上面已经解释了。
我将举例说明“何时使用”。
例如,我们有一个类,其中包含很多资源,例如大数组。
class ResHeavy{ // ResHeavy means heavy resource
public:
ResHeavy(int len=10):_upInt(new int[len]),_len(len){
cout<<"default ctor"<<endl;
}
ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){
cout<<"copy ctor"<<endl;
}
ResHeavy& operator=(const ResHeavy& rhs){
_upInt.reset(new int[rhs._len]);
_len = rhs._len;
cout<<"operator= ctor"<<endl;
}
ResHeavy(ResHeavy&& rhs){
_upInt = std::move(rhs._upInt);
_len = rhs._len;
rhs._len = 0;
cout<<"move ctor"<<endl;
}
// check array valid
bool is_up_valid(){
return _upInt != nullptr;
}
private:
std::unique_ptr<int[]> _upInt; // heavy array resource
int _len; // length of int array
};
Run Code Online (Sandbox Code Playgroud)
测试代码:
void test_std_move2(){
ResHeavy rh; // only one int[]
// operator rh
// after some operator of rh, it becomes no-use
// transform it to other object
ResHeavy rh2 = std::move(rh); // rh becomes invalid
// show rh, rh2 it valid
if(rh.is_up_valid())
cout<<"rh valid"<<endl;
else
cout<<"rh invalid"<<endl;
if(rh2.is_up_valid())
cout<<"rh2 valid"<<endl;
else
cout<<"rh2 invalid"<<endl;
// new ResHeavy object, created by copy ctor
ResHeavy rh3(rh2); // two copy of int[]
if(rh3.is_up_valid())
cout<<"rh3 valid"<<endl;
else
cout<<"rh3 invalid"<<endl;
}
Run Code Online (Sandbox Code Playgroud)
输出如下:
default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid
Run Code Online (Sandbox Code Playgroud)
我们可以看到,std::move通过with move constructor可以轻松地转换资源。
还有什么std::move有用的地方?
std::move在对元素数组进行排序时也很有用。许多排序算法(例如选择排序和冒泡排序)通过交换元素对来工作。以前,我们不得不诉诸于复制语义来进行交换。现在,我们可以使用更有效的移动语义。
如果我们想将一个智能指针管理的内容移动到另一个智能指针,则它也很有用。
引用:
| 归档时间: |
|
| 查看次数: |
242131 次 |
| 最近记录: |