C++ make unique
C++ make_unique[编辑 | 编辑源代码]
介绍[编辑 | 编辑源代码]
make_unique 是 C++14 引入的一个实用函数模板,用于创建并返回一个指向新对象的 std::unique_ptr
。它是现代 C++ 中智能指针工具集的重要组成部分,旨在提供一种更安全、更高效的方式来管理动态分配的内存,避免内存泄漏和裸指针的使用。
std::make_unique
的主要优势包括:
- 减少显式的
new
和delete
操作,降低内存泄漏的风险。 - 提供异常安全性,确保在构造函数抛出异常时不会泄漏内存。
- 代码更简洁,避免重复书写类型名称。
语法[编辑 | 编辑源代码]
make_unique
的基本语法如下:
template< class T, class... Args >
std::unique_ptr<T> make_unique( Args&&... args );
其中:
T
是要创建对象的类型。Args
是传递给T
的构造函数的参数列表。
基本用法[编辑 | 编辑源代码]
创建单个对象[编辑 | 编辑源代码]
最简单的用法是创建一个动态分配的单一对象:
#include <memory>
#include <iostream>
struct Point {
int x, y;
Point(int x, int y) : x(x), y(y) {}
};
int main() {
auto ptr = std::make_unique<Point>(3, 4);
std::cout << "Point: (" << ptr->x << ", " << ptr->y << ")\n";
return 0;
}
输出:
Point: (3, 4)
创建数组[编辑 | 编辑源代码]
make_unique
也可以用于创建动态数组:
#include <memory>
#include <iostream>
int main() {
auto arr = std::make_unique<int[]>(5); // 创建包含5个int的数组
for (int i = 0; i < 5; ++i) {
arr[i] = i * 10;
}
for (int i = 0; i < 5; ++i) {
std::cout << arr[i] << " ";
}
return 0;
}
输出:
0 10 20 30 40
与直接使用 new 的对比[编辑 | 编辑源代码]
传统方式使用 new
创建 unique_ptr
:
std::unique_ptr<Point> ptr(new Point(3, 4));
使用 make_unique
的改进版本:
auto ptr = std::make_unique<Point>(3, 4);
优势对比: 1. 更简洁,不需要重复类型名称 2. 更安全,避免了潜在的异常安全问题 3. 更高效,可能减少内存分配次数
异常安全性[编辑 | 编辑源代码]
make_unique
提供了更强的异常安全性。考虑以下可能不安全的代码:
void unsafe_function(int a, int b) {
some_function(std::unique_ptr<Point>(new Point(a, b)), std::unique_ptr<Point>(new Point(b, a)));
}
如果其中一个 new
成功而另一个抛出异常,则可能发生内存泄漏。使用 make_unique
可以避免这个问题:
void safe_function(int a, int b) {
some_function(std::make_unique<Point>(a, b), std::make_unique<Point>(b, a));
}
实际应用案例[编辑 | 编辑源代码]
工厂模式[编辑 | 编辑源代码]
make_unique
非常适合用于工厂方法:
#include <memory>
#include <iostream>
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
void draw() override { std::cout << "Drawing a circle\n"; }
};
class Square : public Shape {
public:
void draw() override { std::cout << "Drawing a square\n"; }
};
enum class ShapeType { Circle, Square };
std::unique_ptr<Shape> create_shape(ShapeType type) {
switch (type) {
case ShapeType::Circle: return std::make_unique<Circle>();
case ShapeType::Square: return std::make_unique<Square>();
}
return nullptr;
}
int main() {
auto circle = create_shape(ShapeType::Circle);
auto square = create_shape(ShapeType::Square);
circle->draw();
square->draw();
return 0;
}
输出:
Drawing a circle Drawing a square
资源管理[编辑 | 编辑源代码]
make_unique
可以用于管理各种资源:
#include <memory>
#include <fstream>
class FileHandler {
std::unique_ptr<std::fstream> file;
public:
FileHandler(const std::string& filename)
: file(std::make_unique<std::fstream>(filename)) {
if (!file->is_open()) {
throw std::runtime_error("Failed to open file");
}
}
// ... 其他文件操作方法
};
性能考虑[编辑 | 编辑源代码]
make_unique
通常比直接使用 new
更高效,因为:
1. 它允许编译器进行更好的优化
2. 它可能减少内存分配的次数(通过合并分配)
3. 它避免了某些类型的重复计算
限制[编辑 | 编辑源代码]
1. 不能用于需要自定义删除器的场景
2. 不能直接用于需要共享所有权的情况(此时应使用 make_shared
)
3. C++14 之前的标准不支持(但可以自己实现)
自定义实现(C++11兼容)[编辑 | 编辑源代码]
如果你需要使用 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)...));
}
总结[编辑 | 编辑源代码]
std::make_unique
是现代 C++ 中创建 unique_ptr
的推荐方式,它提供了:
- 更简洁的语法
- 更好的异常安全性
- 更高的代码可读性
- 潜在的性能优势
在大多数情况下,应该优先使用 make_unique
而不是直接使用 new
来创建 unique_ptr
。