什么时候需要使用移动构造函数

一、什么时候需要使用移动构造函数?

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;
    }); // 排序过程中会调用移动构造函数

二、什么情况不需要使用移动构造?

  1. 类的成员函数是简单值类型
  2. 类的成员函数是vector/string这种容器,有自己的移动构造
  3. 不可移动和拷贝的类型

总结:类包含原始指针管理动态内存、文件句柄、网络连接资源,必须自定义移动构造函数。

只包含基本类型、stl容器、unique_ptr、shared_ptr不需要自定义

stl容器、unique_ptr、shared_ptr内部有自己的,会自动使用

三、vector什么情况 不会自动使用移动构造函数?

  1. 元素类型没有移动构造函数
  2. 移动构造函数不是 noexcept
  3. 使用 insert 和 push插入已存在对象
  4. 旧编译器或禁用 C++11 特性
  5. 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的区别

  1. push_back:传递已构造的对象
  2. emplace_back:传递构造参数
cpp
// 需要先构造对象,再传递给vector
vector.push_back(MyType(1, 2, 3));  // 先构造临时对象,再移动

过程: 构造对象 → 传递对象 → vector内部拷贝/移动

// 直接传递构造参数,vector内部构造对象
vector.emplace_back(1, 2, 3);  // 直接在vector内存中构造

过程: 传递参数 → vector内部直接构造,调用构造函数,不涉及移动/拷贝构造函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值