未提供移动构造函数时使用std::move的行为及相关问题咨询
C++中未定义移动构造函数时的std::move行为与默认移动构造函数解析
先看你给出的代码场景:
你定义的类:
class myClass { int x[1000]; public: int &getx(int i) { return x[i]; } };
然后执行:
myClass A; auto B = std::move(A);
第一个问题:此时是移动A到B,还是执行拷贝?
答案是:会执行移动操作,而不是拷贝——因为编译器会为你的类生成一个默认的移动构造函数,哪怕你没显式定义它。
不过这里要注意,你的类里的成员是固定大小的数组int x[1000],默认移动构造函数对这种内置类型数组的处理方式其实是逐元素拷贝(因为数组本身是对象内存块的一部分,无法被“移动”)。但这依然属于移动构造的范畴,只是对于这种非动态分配的成员,移动和拷贝的效果看起来一致,底层逻辑上编译器是按照移动语义生成代码的,不会因为你没写移动构造就退化成拷贝构造。
第二个问题:对象是否存在默认移动构造函数?它针对指针及动态分配数组的工作机制是怎样的?
- 默认移动构造函数的存在条件:当你的类没有显式声明任何拷贝构造、拷贝赋值、移动赋值、析构函数时,编译器会自动生成默认的移动构造函数。如果显式声明了上述任何一个,默认移动构造函数就不会被生成(C++11及以后的规则)。
- 针对指针和动态分配数组的工作机制:
- 默认移动构造函数会对类的每个成员执行“逐成员移动”:
- 对于内置类型指针(比如
int* p),它会直接拷贝指针的内存地址值,不会拷贝指针指向的内容。这里要注意:默认移动构造函数不会把原对象的指针置为nullptr,这会导致原对象和新对象的指针指向同一块内存。如果这块内存是动态分配的,两个对象析构时就会触发双重释放的未定义行为。 - 对于动态分配的数组(比如
int* arr = new int[10]),默认移动构造函数同样只会拷贝指针本身,不会移动数组的内容。所以如果你的类管理动态分配资源,绝对不能依赖默认移动构造函数,必须自己显式定义移动构造函数,接管内存并将原对象的指针置为nullptr,避免资源泄漏或双重释放。
- 对于内置类型指针(比如
- 默认移动构造函数会对类的每个成员执行“逐成员移动”:
举个反例,如果你的类是这样的:
class MyDynamicClass { int* arr; size_t size; public: MyDynamicClass(size_t s) : size(s), arr(new int[s]) {} // 未显式定义移动构造,编译器会生成默认版本 ~MyDynamicClass() { delete[] arr; } };
这时用std::move移动对象的话,原对象和新对象的arr会指向同一块内存,析构时必然触发错误。正确的做法是显式写移动构造:
MyDynamicClass(MyDynamicClass&& other) noexcept : arr(other.arr), size(other.size) { other.arr = nullptr; // 让原对象不再持有内存所有权 other.size = 0; }
内容的提问来源于stack exchange,提问作者mans
相关产品推荐
相关产品推荐

