【问题标题】:what will happen when std::move with c style array or not movable object当 std::move 使用 c 样式数组或不可移动对象时会发生什么
【发布时间】:2020-10-18 10:56:09
【问题描述】:
对于c风格的数组,会发生什么 float *fp1 = std::move(fp);如下代码(1),和float *fp1 = fp; 一样吗?如下代码(2),我打印结果,似乎它们是相同的。一般来说,如果对象不可移动,std::move 什么都不做,对吧?
int main(){
float *fp = new float[20];
//float *fp1 = std::move(fp); //(1)
float *fp1 = fp; //(2)
std::cout << "fp: " <<fp << " fp1: "<< fp1<< std::endl;
unique_ptr<float> u_fp(fp);
cout << "u_fp : "<< u_fp.get()<<endl;
unique_ptr<float> u_fp1 = std::move(u_fp);
}
【问题讨论】:
标签:
c++
unique-ptr
stdmove
【解决方案1】:
对于float *fp = new float[20];,fp 不是数组,而是指向包含 20 个浮点对象的数组的第一个元素的指针。您可以显示sizeof(fp) 以确保。
指针确实是可移动的类型,简单地移动或复制它是完全一样的操作。不可移动类型是禁止移动赋值的类型,要么通过明确删除移动赋值运算符,要么因为移动它会移动不可移动的子对象。尝试移动不可移动的对象会导致编译错误。
顺便说一句,如果你试图移动一个真正的 C 数组,它会衰减到一个指针,它和第一种情况一样:
float arr[20];
float *fp1 = std::move(arr); // arr decays to a pointer so the same as fp1 = arr
【解决方案2】:
一般来说,如果对象不可移动,std::move 将什么也不做,对吧?
std::move 只是对右值引用的强制转换,表示您可以丢失其参数中的值。由构造函数或赋值运算符来做一些特殊的事情。一般来说,您可以期望 std::move 的参数在此之后处于有效但未定义的状态,因此执行其析构函数或重置它都应该没问题,但除了谁知道。
由于像指针这样的简单数据类型没有重载的构造函数或赋值运算符,因此强制转换在这里没有任何作用,并且您确实得到了一个简单的赋值。
我会使用术语“可移动类型”作为“可复制”的超集。任何可以复制的类型,您都可以通过复制它然后摆脱原件来移动。有些类型可以移动但不能复制;对于那些std::move 来说特别重要。有些类型你甚至不能移动,它们会将构造函数标记为已删除或私有。 cppreference 同意声明可复制类型也是可移动的。
还请注意,许多容器类型是可复制的(如果它们的元素是),但复制它们比移动它们更昂贵。所以说std::move 只与不可复制的可移动类型有关是错误的。