一、什么时候需要使用移动构造函数?
1. 需要自己管理资源的大型对象
int* buffer;
LargeBuffer buffer1(1000000); // 分配100万个int
2. STL容器中的元素操作
容器扩容/添加元素自动调用移动构造
// 有移动构造函数:高效转移
strings.push_back(std::move(temp)); // 移动构造
// 在vector扩容时,移动构造函数被自动调用
std::vector<MyString> largeVector;
for (int i = 0; i < 1000; ++i) {
largeVector.push_back(MyString("Element " + std::to_string(i)));
// 临时对象直接移动,避免拷贝
}
3. 函数的返回值是大对象
// 返回大型对象的最佳实践
MyString createString() {
MyString result("This is a very long string...");
// ... 一些操作
return result; // 编译器可能使用移动构造(RVO优化失败时)
}
void useCreatedString() {
// 如果没有移动构造函数:可能触发拷贝
// 有移动构造函数:保证高效转移
MyString s = createString(); // 可能调用移动构造
}
```## 标题
**4. 标准库算法的返回值**
```clike
// 在重新排列元素时,标准库会使用移动语义
std::sort(vec.begin(), vec.end(),
[](const MyString& a, const MyString& b) {
return a < b;
}); // 排序过程中会调用移动构造函数
二、什么情况不需要使用移动构造?
- 类的成员函数是简单值类型
- 类的成员函数是vector/string这种容器,有自己的移动构造
- 不可移动和拷贝的类型
总结:类包含原始指针管理动态内存、文件句柄、网络连接资源,必须自定义移动构造函数。
只包含基本类型、stl容器、unique_ptr、shared_ptr不需要自定义
stl容器、unique_ptr、shared_ptr内部有自己的,会自动使用
三、vector什么情况 不会自动使用移动构造函数?
- 元素类型没有移动构造函数
- 移动构造函数不是 noexcept
- 使用 insert 和 push插入已存在对象
- 旧编译器或禁用 C++11 特性
- vector 重新分配时的决策过程
1)、vector的重分配?
涉及扩容操作的,都涉及重分配;
不涉及扩容操作,整个vector移动,不涉及重分配;
重新分配 = 容量不够 → 找新家 → 全员搬家 → 拆旧家
不重新分配 = 要么空间够用,要么整个vector被直接转移
2)、什么情况vector使用移动构造函数,依赖元素的移动构造函数?
1、vector内存的移动不依赖元素,如:
cpp
std::vector<MyType> vec1 = {...};
std::vector<MyType> vec2 = std::move(vec1); // 这里!
这是管理权的转移,不依赖;
效果:vec1把内存指针交给vec2,vec1变空
2、vector重新分配时的元素移动(依赖元素)
扩容时,是将原来的元素,一个一个移动到新内存,涉及元素的移动构造函数;
如果元素没有移动构造函数,则使用拷贝构造函数;
也就是,涉及向容器添加元素时,依赖元素类型的移动构造,不涉及添加元素只是容器的管理权的转移完全不依赖,直接使用vector的移动构造;
3)元素移动构造函数必须声明noexcept,容器才会优先使用移动构造函数,否则会使用元素的拷贝构造函数;
编译器为了安全起见,声明了编译器才认为你这是安全的,否则使用移动构造函数过程中,有可能抛异常,若抛异常,前4个元素已经移动,状态无法恢复,容器需要保证,要么全部移动成功,要么失败全部回滚;
4). 使用 insert 和 push插入已存在对象
a. 插入已存在对象(左值),调用拷贝构造函数,因为不能让原对象失效;
cpp
MyType existing_obj; // 已存在的对象
vector.insert(position, existing_obj); // 插入existing_obj本身
b. 插入新对象或移动对象,调用移动构造函数,因为不需要保持原对象不变
cpp
vector.insert(position, MyType{}); // 插入临时新对象
// 或者
vector.insert(position, std::move(existing_obj)); // 移动existing_obj
四、push_back和emplace_back的区别
- push_back:传递已构造的对象
- emplace_back:传递构造参数
cpp
// 需要先构造对象,再传递给vector
vector.push_back(MyType(1, 2, 3)); // 先构造临时对象,再移动
过程: 构造对象 → 传递对象 → vector内部拷贝/移动
// 直接传递构造参数,vector内部构造对象
vector.emplace_back(1, 2, 3); // 直接在vector内存中构造
过程: 传递参数 → vector内部直接构造,调用构造函数,不涉及移动/拷贝构造函数

286

被折叠的 条评论
为什么被折叠?



