一、std::unique_ptr
- 独占所有权:
std::unique_ptr
拥有对其管理的对象的唯一所有权,意味着没有两个std::unique_ptr
指针可以指向同一个对象。 - 自动释放内存:当
std::unique_ptr
离开作用域或者被显式删除时,它所管理的对象会被自动删除(通过调用delete
操作符)。 - 不能复制,只能移动:
std::unique_ptr
不能被复制,但它可以通过移动语义(C++11 新引入的特性)来转移所有权。这确保了对象的唯一所有权。 - 定制删除器:你可以为
std::unique_ptr
指定一个自定义删除器,在析构时使用这个删除器来释放资源。 - 更低的开销:相对于
std::shared_ptr
,std::unique_ptr
通常有更低的内存和性能开销,因为它不需要维护引用计数。
使用场景:当你需要确保对象不会被多个指针共享,而且你想要自动管理资源时,std::unique_ptr
是一个很好的选择。
二、std::shared_ptr
- 共享所有权:
std::shared_ptr
允许多个指针实例共享对同一个对象的所有权。每个std::shared_ptr
的复制都会增加一个内部引用计数。 - 自动释放内存:只有当最后一个
std::shared_ptr
指向对象的时候,对象才会被自动删除(通过调用delete
操作符)。 - 可复制和移动:
std::shared_ptr
支持复制和移动操作。复制时会增加引用计数,移动不会。 - 线程安全:
std::shared_ptr
在修改对象的引用计数时是线程安全的,但这不代表它所指向的对象的操作也是线程安全的。 - 有开销:由于需要管理引用计数,
std::shared_ptr
相对于std::unique_ptr
有更大的内存和性能开销
使用场景:当你想要在应用程序中的多个部分之间共享对同一个对象的访问,且无需担心对象何时应该释放时,std::shared_ptr
很有用
三、代码举例
std::unique_ptr:
假设你有一个 Widget
类,并且要确保一个 Widget
在任何时候只由一个拥有者控制。比如你希望在一个函数中创建一个 Widget
的实例,并通过某些条件传递给另一个函数。
#include <iostream>
#include <memory>
class Widget {
public:
Widget() { std::cout << "Widget constructed\n"; }
~Widget() { std::cout << "Widget destroyed\n"; }
void doSomething() { std::cout << "Doing something\n"; }
};
void processWidget(std::unique_ptr<Widget> widgetPtr) {
widgetPtr->doSomething();
}
int main() {
std::unique_ptr<Widget> myWidgetPtr = std::make_unique<Widget>();
// myWidgetPtr->doSomething();
// Transfer ownership to processWidget function
processWidget(std::move(myWidgetPtr));
if (!myWidgetPtr) {
std::cout << "myWidgetPtr no longer owns the Widget\n";
}
// If we uncomment the next line, it would not compile,
// because you cannot copy a unique_ptr:
// std::unique_ptr<Widget> anotherWidgetPtr = myWidgetPtr; // Compile error
return 0;
}
在这个例子中,myWidgetPtr
唯一地拥有 Widget
对象。当我们把它传递给 processWidget
函数时,我们使用 std::move
函数来转移所有权。一旦转移完成,myWidgetPtr
将不再拥有 Widget
对象。
std::shared_ptr:
#include <iostream>
#include <memory>
class Widget {
public:
Widget() { std::cout << "Widget constructed\n"; }
~Widget() { std::cout << "Widget destroyed\n"; }
void doSomething() { std::cout << "Doing something\n"; }
};
void processWidget(std::shared_ptr<Widget> widgetPtr) {
std::cout << "Shared widget, use count: " << widgetPtr.use_count() << '\n';
widgetPtr->doSomething();
}
int main() {
std::shared_ptr<Widget> myWidgetPtr = std::make_shared<Widget>();
{
std::shared_ptr<Widget> myOtherWidgetPtr = myWidgetPtr;
processWidget(myOtherWidgetPtr);
std::cout << "Shared widget, use count inside scope: " << myWidgetPtr.use_count() << '\n';
} // myOtherWidgetPtr goes out of scope here, decrementing use count
std::cout << "Shared widget, use count outside scope: " << myWidgetPtr.use_count() << '\n';
myWidgetPtr->doSomething();
return 0;
}
在这个示例中,myWidgetPtr
是一个 std::shared_ptr
,它共享拥有 Widget
对象。在代码块中,创建了一个 myOtherWidgetPtr
的拷贝,它和 myWidgetPtr
共享对同一个 Widget
对象的拥有权,并且内部引用计数增加。当 myOtherWidgetPtr
离开作用域时,引用计数减少,但因为 myWidgetPtr
仍然存在,所以 Widget
对象不会被删除。只有当所有 std::shared_ptr
实例都超出作用域,最后一个 std::shared_ptr
被销毁时,Widget
对象才会被删除。
四、std::enable_shared_from_this
std::enable_shared_from_this
是一个模板辅助类,它允许一个对象(由其自身的 std::shared_ptr
所拥有)安全地生成额外的 std::shared_ptr
实例,这些实例与初始的 std::shared_ptr
共享同样的控制块。
当您想在类内部获得指向当前对象的 std::shared_ptr
指针时,这非常有用,尤其是在您想在外部以 std::shared_ptr
接口管理对象生命周期的情况下。
下面是一个使用 std::enable_shared_from_this
的类的示例:
#include <memory>
class ACDCChargeTask : public std::enable_shared_from_this<ACDCChargeTask> {
public:
// 类成员函数和变量
std::shared_ptr<ACDCChargeTask> getSharedThis() {
return shared_from_this(); // 返回一个指向当前对象的 std::shared_ptr
}
void someOtherFunction() {
// 您可能需要在这里使用 shared_from_this() 的返回值
auto sharedPtrToThis = shared_from_this();
// 使用 sharedPtrToThis 做一些工作
}
// 更多类成员和函数...
};
在这个示例中,ACDCChargeTask
类通过公开继承 std::enable_shared_from_this
获得了 shared_from_this
方法,该方法可以用于获取指向当前对象 this
的 std::shared_ptr
。
请注意,为了安全使用 shared_from_this
,对象必须已经被 std::shared_ptr
管理。也就是说,在使用 shared_from_this
方法之前,对象应该已经以 std::shared_ptr
形式存在。否则,调用 shared_from_this
将导致 std::bad_weak_ptr
异常。下面是如何正确创建并使用这个类的实例:
std::shared_ptr<ACDCChargeTask> task = std::make_shared<ACDCChargeTask>();
auto anotherSharedPtr = task->getSharedThis();
在这里,task
是一个 std::shared_ptr<ACDCChargeTask>
,它拥有 ACDCChargeTask
的一个实例。之后,通过 task
调用 getSharedThis
方法返回了一个新的 std::shared_ptr<ACDCChargeTask>
,它与 task
共享拥有权。