推荐使用std::make_unique创建unique_ptr,因其将对象构造与智能指针创建封装为原子操作,避免因函数参数求值顺序不确定导致的异常安全问题,同时提升代码简洁性与可读性。

现代C++中推荐使用
std::make_unique
unique_ptr
new
unique_ptr
当我们谈论
unique_ptr
std::unique_ptr<MyClass> ptr(new MyClass());
考虑一个函数调用,其中包含多个参数,例如:
some_function(std::unique_ptr<MyClass>(new MyClass()), another_function_that_might_throw());
C++标准对函数参数的求值顺序并没有严格规定,只知道在调用
some_function
new MyClass()
another_function_that_might_throw()
std::unique_ptr<MyClass>(...)
MyClass
如果执行顺序是1 -> 2 -> 3,并且
another_function_that_might_throw()
unique_ptr
new MyClass()
new
unique_ptr
立即学习“C++免费学习笔记(深入)”;
而
std::make_unique
unique_ptr
std::make_unique<MyClass>()
MyClass
unique_ptr
std::make_unique
new
unique_ptr
例如,对于
func(A(), B(), C())
new MyObject()
another_risky_call()
std::unique_ptr<MyObject>(...)
new MyObject()
another_risky_call()
std::unique_ptr
MyObject
std::make_unique
new
unique_ptr
std::make_unique<MyClass>(args...)
new MyClass(args...)
unique_ptr
make_unique
unique_ptr
MyClass
new
这使得像下面这样的代码变得安全:
void process_data(std::unique_ptr<Data> p, int value); void potentially_failing_operation(); // 不安全的方式 // process_data(std::unique_ptr<Data>(new Data()), potentially_failing_operation()); // 如果 Data 的 new 完成了,但 potentially_failing_operation() 抛出,Data 会泄露。 // 安全的方式 process_data(std::make_unique<Data>(), potentially_failing_operation()); // make_unique 确保 Data 对象要么被 unique_ptr 拥有,要么在创建过程中失败,不会出现中间状态的泄露。
这种设计极大地简化了对异常安全性的考量,让开发者能更专注于业务逻辑,而不是底层内存管理的复杂性。
除了异常安全性这个核心优势,
std::make_unique
首先,代码的简洁性和可读性得到了显著提升。对比一下两种创建方式:
// 旧方式 std::unique_ptr<MyComplexType> ptr1(new MyComplexType(arg1, arg2, arg3)); // 推荐方式 std::unique_ptr<MyComplexType> ptr2 = std::make_unique<MyComplexType>(arg1, arg2, arg3);
很明显,第二种方式更加简洁。它避免了重复写入类型名称
MyComplexType
MyComplexType
其次,它与std::make_shared
std::make_shared
std::shared_ptr
std::make_unique
虽然对于
unique_ptr
make_unique
make_shared
unique_ptr
make_unique
make_unique
尽管
std::make_unique
unique_ptr
new
unique_ptr
最常见的情况是当需要使用自定义deleter时。
std::make_unique
unique_ptr
FILE*
fclose
#include <cstdio>
#include <memory>
// 自定义 deleter 函数
void file_closer(FILE* f) {
if (f) {
fclose(f);
}
}
int main() {
// 无法使用 make_unique
// std::unique_ptr<FILE, decltype(&file_closer)> log_file = std::make_unique<FILE>(fopen("log.txt", "w"), &file_closer); // 错误
// 必须直接使用 new (或者这里是 fopen 返回的指针)
std::unique_ptr<FILE, decltype(&file_closer)> log_file(fopen("log.txt", "w"), &file_closer);
if (log_file) {
fprintf(log_file.get(), "Hello from unique_ptr!\n");
}
// log_file 在离开作用域时会自动关闭文件
return 0;
}这里,
fopen
FILE*
unique_ptr
file_closer
另一个场景是当需要从一个已存在的原始指针接管所有权时。这可能发生在与遗留C++代码库交互,或者当一个工厂函数返回一个
new
// 假设这是一个C风格的API,返回一个 new 出来的对象
MyClass* create_my_class_raw() {
return new MyClass();
}
int main() {
MyClass* raw_ptr = create_my_class_raw();
// 此时不能用 make_unique,因为它会再次 new 一个对象
std::unique_ptr<MyClass> managed_ptr(raw_ptr);
// managed_ptr 现在拥有了 raw_ptr 指向的对象
return 0;
}在这种情况下,我们不是要“创建”一个新的对象,而是要“接管”一个已经存在的对象的所有权,所以直接将原始指针传递给
unique_ptr
最后,当处理unique_ptr
std::make_unique
std::make_unique<T[]>(size)
delete[]
new T[size]
unique_ptr<T[], MyCustomArrayDeleter>
这些情况虽然相对小众,但确实存在,提醒我们
std::make_unique
以上就是为什么现代C++推荐使用std::make_unique来创建unique_ptr的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号