两种智能指针的区别和选择方式
std::unique_ptr
和 std::shared_ptr
是C++标准库中的两种不同类型的智能指针,它们有一些关键的区别。以下是它们之间的主要区别:
-
所有权:
std::unique_ptr
: 拥有独占所有权,一个std::unique_ptr
实例是唯一能够拥有和管理其指向对象的所有权。当std::unique_ptr
被销毁时,它拥有的对象也会被销毁。std::shared_ptr
: 允许多个std::shared_ptr
实例共享同一个对象的所有权。通过引用计数机制,当最后一个std::shared_ptr
被销毁时,才会销毁共享的对象。
-
性能开销:
std::unique_ptr
: 通常比std::shared_ptr
更轻量,因为它不需要维护引用计数。std::shared_ptr
: 使用引用计数来跟踪共享的所有权,可能会带来额外的性能开销。
-
内存管理:
std::unique_ptr
: 适用于独占所有权的场景,一般用于管理单一对象或数组。std::shared_ptr
: 适用于共享所有权的场景,可用于在多个地方访问相同的对象。
-
创建方式:
std::unique_ptr
: 使用std::make_unique
或直接使用new
操作符创建。std::shared_ptr
: 使用std::make_shared
或直接使用new
操作符创建。
-
传递所有权:
std::unique_ptr
: 可以通过移动语义来传递所有权,不能直接进行拷贝。std::shared_ptr
: 可以通过拷贝来传递所有权,引用计数会相应地增加。
-
循环引用:
std::unique_ptr
: 不涉及循环引用的问题,因为它是独占所有权的。std::shared_ptr
: 可能引入循环引用的问题,需要注意使用std::weak_ptr
来打破循环引用。
-
线程安全性:
std::unique_ptr
: 不提供多线程访问的保护。std::shared_ptr
: 提供了引用计数的原子操作,可以在多线程环境下安全使用。
在选择使用 std::unique_ptr
还是 std::shared_ptr
时,取决于你的设计需求。如果能够确定对象拥有独占的所有权,并且不需要共享,那么 std::unique_ptr
是更轻量和合适的选择。如果需要在多个地方共享对象,并希望方便地传递所有权,那么 std::shared_ptr
是一个更适合的选择。
share_ptr 示例 独占权所以不能建多个指针
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass(int val) : value(val) {
std::cout << "Constructor. Value: " << value << std::endl;
}
~MyClass() {
std::cout << "Destructor. Value: " << value << std::endl;
}
void someFunction() {
std::cout << "Some function. Value: " << value << std::endl;
}
private:
int value;
};
int main() {
// 创建一个 std::shared_ptr,多个指针共享所有权的 MyClass 对象
std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(42);
// 使用 std::shared_ptr 指向的资源
sharedPtr->someFunction();
// 在此处创建一个新的 std::shared_ptr,共享相同的资源
std::shared_ptr<MyClass> sharedPtr2 = sharedPtr;
sharedPtr2->someFunction();
// 在此处创建一个新的 std::shared_ptr,共享相同的资源
std::shared_ptr<MyClass> sharedPtr3 = sharedPtr;
sharedPtr3->someFunction();
// sharedPtr , sharePtr2 和 sharedPtr3 在此处被销毁,动态分配的 MyClass 对象的析构函数被调用
return 0;
}
unique_ptr 指针示例 没有独占权可以建多个指针共享内存,引用计数为0自动销毁
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass(int val) : value(val) {
std::cout << "Constructor. Value: " << value << std::endl;
}
~MyClass() {
std::cout << "Destructor. Value: " << value << std::endl;
}
void someFunction() {
std::cout << "Some function. Value: " << value << std::endl;
}
private:
int value;
};
int main() {
// 创建一个 std::unique_ptr,拥有独占所有权的 MyClass 对象
std::unique_ptr<MyClass> uniquePtr = std::make_unique<MyClass>(42);
// 使用 std::unique_ptr 指向的资源
uniquePtr->someFunction();
// 在此处创建一个新的 std::unique_ptr,尝试共享所有权(编译错误)
//std::unique_ptr<MyClass> anotherUniquePtr = uniquePtr; // 错误!
// uniquePtr 在此处被销毁,动态分配的 MyClass 对象的析构函数被调用
return 0;
}
两种指针比较 实例
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass(int val) : value(val) {
std::cout << "Constructor. Value: " << value << std::endl;
}
~MyClass() {
std::cout << "Destructor. Value: " << value << std::endl;
}
void someFunction() {
std::cout << "Some function. Value: " << value << std::endl;
}
private:
int value;
};
int main() {
// 使用 std::unique_ptr
{
std::cout << "----- Using std::unique_ptr 1st 42 -----" << std::endl;
// 创建一个 std::unique_ptr,拥有一个动态分配的 MyClass 对象
std::unique_ptr<MyClass> uniquePtr = std::make_unique<MyClass>(42);
// 使用 std::unique_ptr 指向的资源
uniquePtr->someFunction();
std::cout << std::endl;
// 使用 std::shared_ptr
{
std::cout << "----- Using std::shared_ptr 2nd 24 -----" << std::endl;
// 创建一个 std::shared_ptr,拥有一个动态分配的 MyClass 对象
std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(24);
// 使用 std::shared_ptr 指向的资源
sharedPtr->someFunction();
// 在此处创建一个新的 sharedPtr2,与 sharedPtr 共享资源
std::shared_ptr<MyClass> sharedPtr2 = sharedPtr;
// sharedPtr 和 sharedPtr2 在此处被销毁,动态分配的 MyClass 对象的析构函数被调用
}
// unique_ptr 1st 在此处被销毁,动态分配的 MyClass 对象的析构函数被调用
}
return 0;
}