第一章 容器

03-确保容器中的对象拷贝正确而高效

STL容器的工作方式是”copy in, copy out”(进去的是副本,出来的也是副本)。这意味着:
1.插入时: push_back() 、 insert() 等操作会把对象拷贝一份存进容器
2.访问时:从容器取出对象也是得到副本
3.内部操作时:排序、删除、反转等算法也会频繁拷贝或移动元素;
在C++11 后,”副本”可以是移动而非拷贝。

三个主要问题与解决方式

1、拷贝引起的性能问题

// 只能拷贝,大对象性能灾难
std::vector<std::string> v;
std::string s(1000000, 'x');
v.push_back(s); // 深拷贝100万个字符

// 方案A:显式移动
v.push_back(std::move(s)); // 转移资源所有权,O(1)

// 方案B:直接构造(最优)
v.emplace_back(1000000, 'x'); // 原地构造,零拷贝零移动

//关键要求:类需要实现移动构造函数和移动赋值运算符
class MyClass {
public:
MyClass(MyClass&& other) noexcept; // 移动构造
MyClass& operator=(MyClass&& other) noexcept; // 移动赋值
};

2、切片问题: 将派生嘞对象存入基类容器,派生部分会被切掉

class Widget { /* ... */ };
class SpecialWidget : public Widget { /* ... */ };

//方案:用 unique_ptr 或 shared_ptr 替代裸指针
// 自动内存管理,无内存泄漏风险
std::vector<std::unique_ptr<Widget>> widgets;
widgets.emplace_back(std::make_unique<SpecialWidget>());

3、移动后的对象处于”有效但未指定状态”

std::vector<std::string> v;
std::string s = "hello";
v.push_back(std::move(s));

// ❌ s 现在处于有效但未指定状态,不要再使用
std::cout << s; // 危险!s 可能为空

//解决方案:移动后立刻让原对象离开作用域, 或显式调用 clear() 后再使用