std::unique_ptr通过独占所有权和RAII原则确保内存安全,禁用拷贝、强制移动语义以防止双重释放,适用于工厂函数、PIMPL、容器存储等场景,相比shared_ptr性能更高且无循环引用风险,但不支持共享所有权。

C++11引入的
std::unique_ptr
std::unique_ptr
独占所有权(Exclusive Ownership):这是
unique_ptr
unique_ptr
unique_ptr
RAII 原则:
unique_ptr
unique_ptr
new
unique_ptr
delete
立即学习“C++免费学习笔记(深入)”;
禁用拷贝语义:
unique_ptr
unique_ptr
unique_ptr
强制移动语义:虽然不能拷贝,但
unique_ptr
std::move
unique_ptr
unique_ptr
unique_ptr
unique_ptr
#include <iostream>
#include <memory> // For std::unique_ptr
class MyClass {
public:
MyClass() { std::cout << "MyClass constructed!\n"; }
~MyClass() { std::cout << "MyClass destructed!\n"; }
void doSomething() { std::cout << "Doing something...\n"; }
};
// 1. 基本使用与RAII
void demonstrateRAII() {
std::cout << "Entering demonstrateRAII...\n";
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(); // 资源获取
ptr->doSomething();
// 当ptr超出作用域时,MyClass的析构函数会被自动调用
std::cout << "Exiting demonstrateRAII...\n";
} // ptr在这里被销毁,MyClass对象被释放
// 2. 移动语义
std::unique_ptr<MyClass> createAndReturn() {
std::cout << "Creating object in createAndReturn...\n";
return std::make_unique<MyClass>(); // 返回一个unique_ptr,所有权被移动
}
void demonstrateMove() {
std::cout << "Entering demonstrateMove...\n";
std::unique_ptr<MyClass> owner = createAndReturn(); // 接收所有权
if (owner) {
owner->doSomething();
}
// owner在这里被销毁
std::cout << "Exiting demonstrateMove...\n";
}
int main() {
demonstrateRAII();
std::cout << "\n------------------\n\n";
demonstrateMove();
return 0;
}这段代码清晰地展示了
unique_ptr
std::unique_ptr
这其实是
unique_ptr
unique_ptr
假设我们有两个
unique_ptr
ptr1
ptr2
new
ptr1
delete
ptr2
delete
所以,为了彻底避免这种内存管理上的混乱,
unique_ptr
unique_ptr
而移动语义(
std::move
unique_ptr
nullptr
unique_ptr
unique_ptr
std::unique_ptr
在实际的C++项目中,我发现
std::unique_ptr
工厂函数返回新创建的对象:这是最经典的场景之一。当一个工厂函数动态创建一个对象并将其所有权移交给调用者时,
unique_ptr
std::unique_ptr<BaseClass> createObject(int type) {
if (type == 1) {
return std::make_unique<DerivedClassA>();
} else {
return std::make_unique<DerivedClassB>();
}
}
// 调用者接收所有权
auto myObj = createObject(1);
myObj->doSomething();这样,调用者无需关心内存释放,
myObj
PIMPL(Pointer to Implementation)惯用法:为了减少编译依赖和隐藏实现细节,PIMPL 是一种常见的设计模式。
unique_ptr
// MyClass.h
class MyClass {
public:
MyClass();
~MyClass(); // 需要定义在.cpp中
void publicMethod();
private:
class Impl; // 前向声明
std::unique_ptr<Impl> pImpl;
};
// MyClass.cpp
class MyClass::Impl { /* ... 具体的实现细节 ... */ };
MyClass::MyClass() : pImpl(std::make_unique<Impl>()) {}
MyClass::~MyClass() = default; // unique_ptr的析构函数会自动调用Impl的析构函数这样,
MyClass
Impl
容器中存储动态分配的对象:当你想在
std::vector
std::list
std::vector<std::unique_ptr<MyObject>>
std::vector<std::unique_ptr<MyClass>> objects; objects.push_back(std::make_unique<MyClass>()); objects.emplace_back(new MyClass()); // 也可以这样 // 当vector被销毁时,所有MyClass对象都会被自动释放
管理非内存资源:
unique_ptr
// 示例:管理文件句柄
struct FileCloser {
void operator()(FILE* fp) const {
if (fp) {
fclose(fp);
std::cout << "File closed!\n";
}
}
};
std::unique_ptr<FILE, FileCloser> filePtr(fopen("example.txt", "w"));
if (filePtr) {
fprintf(filePtr.get(), "Hello, unique_ptr!\n");
}
// filePtr超出作用域时,FileCloser会被调用,文件被关闭这展示了
unique_ptr
局部变量的动态分配:有时,一个大型对象可能不适合放在栈上(例如,大小不确定或非常大),或者你需要多态行为。此时,在函数内部使用
unique_ptr
void processData(bool useSpecialAlgorithm) {
std::unique_ptr<Algorithm> algo;
if (useSpecialAlgorithm) {
algo = std::make_unique<SpecialAlgorithm>();
} else {
algo = std::make_unique<DefaultAlgorithm>();
}
algo->run();
}我个人在编写一些工具类或服务时,如果某个成员变量需要动态分配,并且它的生命周期与宿主对象严格绑定,那么
unique_ptr
delete
std::shared_ptr
unique_ptr
选择智能指针,就像选择一个工具,需要根据具体的场景和需求来决定。
unique_ptr
shared_ptr
unique_ptr
delete
shared_ptr
unique_ptr
unique_ptr
unique_ptr
shared_ptr
weak_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
std::weak_ptr
与原始指针的对比:
unique_ptr
delete
.get()
unique_ptr
与std::shared_ptr
unique_ptr
shared_ptr
对我而言,在项目开发中,我的默认选择通常是
unique_ptr
shared_ptr
shared_ptr
std::weak_ptr
以上就是C++11的std::unique_ptr是如何保证内存安全的的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号