unique_ptr 在 C++14 中的优化

unique_ptr 在 C++14 中的优化
苏丙榅1. unique_ptr
在 C++11 引入智能指针(std::unique_ptr, std::shared_ptr, std::weak_ptr)奠定了现代 C++ 内存管理的基础后,C++14 主要在易用性、性能和功能细节上进行了重要的优化和增强。
在 C++11 中,虽然智能指针 std::unique_ptr 是标准的一部分,但创建它的辅助函数 std::make_unique 直到 C++14 才加入。
1.1 在 C++11 中创建对象
在 C++11 中,创建一个unique_ptr类型的对象我们有以下几种选择:
方案 A:手动实现
make_unique1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// C++11 兼容的 make_unique 实现
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
int main()
{
auto ptr = make_unique<int>(42);
std::cout << "ptr value: " << *ptr.get() << std::endl;
return 0;
}方案 B:直接使用
new1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Widget
{
int id;
std::string name;
Widget(int i, const std::string& n) : id(i), name(n)
{
std::cout << "Widget " << id << " created" << std::endl;
}
};
int main()
{
std::unique_ptr<Widget> ptr1(new Widget(1, "First"));
std::unique_ptr<int> ptr2(new int(19));
return 0;
}
1.2 C++14 中的原生支持
在 C++14 中,标准库中提供了 std::make_unique,它已经已经成为 <memory> 头文件的一部分,可以直接使用,无需额外实现。
1 |
|
使用 std::make_unique 相比于直接使用 new 有以下优势:
- 更好的异常安全性
- 代码更简洁
- 避免手动
new和delete - 支持数组版本
std::make_unique<T[]>
当 std::make_unique 用于创建数组(即 make_unique<T[]>(n))时:
- 它会分配足够存放
n个T对象的内存。 - 它会对数组中的每一个元素调用默认构造函数
T()(值初始化)。 - 它不支持使用括号
()传递参数来初始化数组中的每个元素。
当使用 std::make_unique<int[]> 时,模板参数 T 被推导为 int[]。std::unique_ptr 针对数组类型(T[])有部分特化实现。这个特化版本在析构时会自动调用 delete[],而不需要(也不能)手动指定删除器。
使用
make_unique<int[]>(自动使用默认数组删除器)1
2
3// 编译器知道这是一个数组,std::unique_ptr<int[]> 的析构函数会自动调用 delete[]
auto ptr = std::make_unique<int[]>(10);
// ptr 的类型是 std::unique_ptr<int[]>直接使用
unique_ptr(自动使用默认数组删除器)1
2
3// 只要模板参数写的是 int[],它就会自动匹配数组特化版本,自动调用 delete[]
// 不需要写 std::default_delete<int[]>()
std::unique_ptr<int[]> ptr(new int[10]);如果不小心写成了
unique_ptr<int>(不会使用数组删除器)1
2
3// 这里类型是 int (单个对象),不是 int[]
// 析构时会调用 delete (而不是 delete[])!这会导致未定义行为(通常是内存泄漏或崩溃)
std::unique_ptr<int> ptr(new int[10]);
所以在 C++14 及以后,只要使用 make_unique 创建数组,就不用担心删除器的问题,它是默认提供并且可以正确工作的。
关于智能指针,虽然 C++14 引入了 std::make_unique<T[]>(size_t) 来支持数组,但标准委员会并没有为 std::make_shared 添加类似的数组支持。如果你在 C++14 环境下运行这行代码:
1 | auto ptr5 = std::make_shared<int[]>(12); |
编译器会报错,提示 make_shared 没有匹配 int[] 类型的重载模板,或者提示 shared_ptr 不支持数组类型。如果需要在 C++14 中用共享指针管理数组,必须手动指定删除器,并且类型要写成 shared_ptr<int> 而不是 shared_ptr<int[]>:
1 | // C++14 正确写法:需要指定删除器 |
















