在C++中,智能指针是一种管理动态分配内存的类模板,它能够自动释放所管理的对象,从而避免内存泄漏。C++标准库中提供了几种常用的智能指针。
1. std::unique_ptr
独占所有权:确保同一时间只有一个unique_ptr指向一个特定的资源。
自动释放资源:当unique_ptr超出作用域时,会自动释放所管理的资源。
高效传递所有权:通过std::move可以将资源所有权转移。
不允许复制:只能通过移动语义进行传递。
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass Constructor\n"; }
~MyClass() { std::cout << "MyClass Destructor\n"; }
void show() { std::cout << "MyClass show() function\n"; }
};
int main() {
// 创建 unique_ptr 实例
//std::unique_ptr<MyClass> ptr1(new MyClass()); //不推荐
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(); //推荐
ptr1->show(); // 调用 MyClass 的成员函数
//std::unique_ptr<MyClass> ptr2 = ptr1 // 此语句是错误的, unique_ptr 不支持复制,但支持移动语义
std::unique_ptr<MyClass> ptr2 = std::move(ptr1); // 转移所有权
// 此时 ptr1 不再拥有对象,尝试访问会导致未定义行为
// ptr1->show(); // 不应执行此行
// ptr2 仍然拥有对象,并在离开作用域时自动释放(unique_ptr类型的智能指针的指针变量是ptr2是局部变量,当它离开作用域时,它所指向的堆内存也会被释放)
return 0; // MyClass Destructor 将在此处被调用
}
2. std::shared_ptr
共享所有权:允许多个shared_ptr共同拥有同一块内存。
引用计数:采用引用计数机制,当最后一个shared_ptr离开作用域或被重置时,所管理的资源会被释放。
解决共享资源管理问题:适用于多个对象需要共享同一资源的情况。
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass Constructor\n"; }
~MyClass() { std::cout << "MyClass Destructor\n"; }
void show() { std::cout << "MyClass show() function\n"; }
};
int main() {
// 创建 shared_ptr 实例
//std::shared_ptr<MyClass> ptr1(new MyClass()); //不推荐
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(); //推荐
//局部代码块
{
std::shared_ptr<MyClass> ptr2 = ptr1; // 复制,共享所有权
ptr2->show(); // 调用 MyClass 的成员函数
// 此时 MyClass 对象的引用计数为 2
} // ptr2 离开作用域,引用计数减为 1
ptr1->show(); // 再次调用 MyClass 的成员函数
// ptr1 离开作用域,引用计数减为 0,对象被释放
return 0; // MyClass Destructor 将在此处或稍后被调用(取决于实现)
}
3. std::weak_ptr
弱引用:不共享所有权,用于解决std::shared_ptr循环引用导致的内存泄漏问题。
不增加引用计数:可以从std::shared_ptr创建,但不会增加对象的引用计数。
检查对象状态:可以通过lock函数转换为std::shared_ptr,以安全地访问对象。
是一种不拥有资源的智能指针,它通常与 std::shared_ptr 配合使用,用于解决循环引用问题
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass Constructor\n"; }
~MyClass() { std::cout << "MyClass Destructor\n"; }
void show() { std::cout << "MyClass show() function\n"; }
};
int main() {
// 创建 shared_ptr 实例
//std::shared_ptr<MyClass> sharedPtr(new MyClass()); //不推荐
std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(); //推荐
// 创建 weak_ptr 实例,不增加引用计数
std::weak_ptr<MyClass> weakPtr = sharedPtr;
// 尝试锁定 weak_ptr,获取 shared_ptr
std::shared_ptr<MyClass> lockedPtr = weakPtr.lock();
if (lockedPtr) {
lockedPtr->show(); // 调用 MyClass 的成员函数
} else {//返回一个空的shared_ptr<MyClass>
std::cout << "MyClass object has been destroyed\n";
}
// sharedPtr 离开作用域,引用计数减为 0,对象被释放
return 0; // MyClass Destructor 将在此处被调用
}

先看一个C++中循环引用引起的问题代码示例:
#include <iostream>
#include <memory>
class B; // 前向声明
class A {
public:
std::shared_ptr<B> ptrB; // A拥有一个指向B的shared_ptr
~A() { std::cout << "A destroyed\n"; }
};
class B {
public:
std::shared_ptr<A> ptrA; // B拥有一个指向A的shared_ptr
~B() { std::cout << "B destroyed\n"; }
};
int main() {
{
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->ptrB = b;
b->ptrA = a; // 形成循环引用
// 此时,A类对象和B类对象的引用计数都为2(因为它们相互引用),所以它们都不会被销毁
} // 离开作用域(虽然智能指针局部变量a和b被销毁,但他们所管理的对象并没有销毁),但由于循环引用,A类对象和B类对象并没有被销毁
// 程序结束前,没有输出"A destroyed"和"B destroyed",说明a和b所指向的对象没有被释放
return 0;
}
初始时,a是一个局部变量,a持有一个A对象的智能指针,b也是一个局部变量,b持有一个B对象的智能指针。
当a->ptrB = b;执行时,A对象中的ptrB成员变量持有了b所指向的B对象的智能指针,此时,b所指向的B对象的引用计数增加到2(因为除了b本身,a->ptrB也在引用它)
当b->ptrA = a;执行时,同样地,B对象中的ptrA成员变量持有了a所指向的A对象的智能指针。此时,a所指向的A对象的引用计数也增加到2(因为除了a本身,b->ptrA也在引用它)
std::weak_ptr如何打破循环引用及实例
#include <iostream>
#include <memory>
class B; // 前向声明
class A {
public:
std::shared_ptr<B> ptrB; // A拥有一个指向B的shared_ptr
~A() { std::cout << "A destroyed\n"; }
};
class B {
public:
std::weak_ptr<A> ptrA; // B拥有一个指向A的weak_ptr
~B() { std::cout << "B destroyed\n"; }
};
int main() {
{
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->ptrB = b;
b->ptrA = std::weak_ptr<A>(a); // 注意这里是weak_ptr
// 此时,a和b相互引用,但由于b使用的是weak_ptr,所以不会形成循环引用
} // 离开作用域,a和b所管理的对象都被销毁
// 如果没有weak_ptr,这里a和b会因为循环引用而无法被销毁
return 0;
}
4. std::auto_ptr(已弃用)
独占所有权:类似于std::unique_ptr,但在C++11中被弃用。
所有权转移:赋值操作会将所有权转移,导致原指针失效。
不安全:在多指针场景下容易引发问题,因此被弃用。
3万+

被折叠的 条评论
为什么被折叠?



