C++11-共享指针shared_ptr使用注意事项

两种创建 shared_ptr 的方式
  1. 通过构造函数直接构造 shared_ptr:

    std::shared_ptr<MyClass> ptr(new MyClass(10));
    
    • 内存分配
      • 两次内存分配:一次为对象内存 (new MyClass(10)),一次为控制块内存。
    • 灵活性
      • 允许自定义删除器:
        std::shared_ptr<MyClass> ptr(new MyClass(10), custom_deleter);
        
    • 内存释放
      • 当共享引用计数(shared count)降为零时,调用删除器释放对象内存。
      • 当弱引用计数(weak count)降为零时,释放控制块内存。
  2. 使用 std::make_shared 构造 shared_ptr:

    std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(10);
    
    • 内存分配
      • 一次内存分配:对象和控制块一起分配。
    • 效率
      • 更高效,减少了内存分配次数。
    • 内存释放
      • 当共享引用计数(shared count)降为零时,释放对象和控制块内存。
在有弱指针 (weak_ptr) 使用时的内存释放时机
  • 通过构造函数直接构造 shared_ptr

    • 当共享引用计数(shared count)降为零时:
      • 对象内存被释放,但控制块内存保留,直到弱引用计数(weak count)也降为零。
    • 当弱引用计数(weak count)降为零时:
      • 控制块内存被释放。
  • 使用 std::make_shared 构造 shared_ptr

    • 当共享引用计数(shared count)降为零时:
      • 对象会被调用析构函数,但内存暂时不会被释放,只有等到共享引用计数和弱引用计数同时为零时才会释放对象内存和控制块内存。

详细比较

  • 内存分配

    • 构造函数
      • 分配两次内存,一次给对象,一次给控制块。
    • make_shared
      • 一次内存分配,对象和控制块在同一块内存中。
  • 内存释放

    • 构造函数
      • 共享引用计数为零时释放对象内存。
      • 弱引用计数为零时释放控制块内存。
    • make_shared
      • 共享引用计数和弱引用计数同时为零时同时释放对象和控制块内存。
  • 灵活性和异常安全性

    • 构造函数
      • 允许自定义删除器,适用于需要特殊资源管理的场景。
      • 在对象和控制块分开分配时,构造过程中抛出异常可能导致内存泄漏。
    • make_shared
      • 不允许自定义删除器,但在大多数情况下提供了更高效的内存管理。
      • 提供更好的异常安全性,因为对象和控制块一起分配。

示例代码

通过构造函数直接构造 shared_ptrweak_ptr
#include <memory>
#include <iostream>

class MyClass {
public:
    MyClass(int value) : value(value) {
        std::cout << "MyClass constructed\n";
    }
    ~MyClass() {
        std::cout << "MyClass destroyed\n";
    }
private:
    int value;
};

int main() {
    std::shared_ptr<MyClass> ptr(new MyClass(10));
    std::weak_ptr<MyClass> weakPtr = ptr;

    std::cout << "Shared Count: " << ptr.use_count() << "\n"; // 应为1

    // Reset shared_ptr to test destruction
    ptr.reset();
    std::cout << "Shared Count after reset: " << ptr.use_count() << "\n"; // 应为0

    // weak_ptr still keeps control block alive
    if (auto shared = weakPtr.lock()) {
        std::cout << "Weak pointer still valid.\n";
    } else {
        std::cout << "Weak pointer expired.\n";
    }
    return 0;
}
使用 std::make_shared 构造 shared_ptrweak_ptr
#include <memory>
#include <iostream>

class MyClass {
public:
    MyClass(int value) : value(value) {
        std::cout << "MyClass constructed\n";
    }
    ~MyClass() {
        std::cout << "MyClass destroyed\n";
    }
private:
    int value;
};

int main() {
    std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(10);
    std::weak_ptr<MyClass> weakPtr = ptr;

    std::cout << "Shared Count: " << ptr.use_count() << "\n"; // 应为1

    // Reset shared_ptr to test destruction
    ptr.reset();
    std::cout << "Shared Count after reset: " << ptr.use_count() << "\n"; // 应为0

    // weak_ptr still keeps control block alive
    if (auto shared = weakPtr.lock()) {
        std::cout << "Weak pointer still valid.\n";
    } else {
        std::cout << "Weak pointer expired.\n";
    }
    return 0;
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`std::shared_ptr` 和 `std::make_shared` 是 C++11 引入的智能指针相关的类和函数,它们用于管理动态分配的内存资源。下面是一些使用注意事项: 1. 避免循环引用:`std::shared_ptr` 使用引用计数来管理资源,当资源的引用计数为0时,资源会被释放。如果存在互相引用的情况(循环引用),资源将永远无法被释放,导致内存泄漏。因此,在设计和使用 `std::shared_ptr` 时,要避免循环引用。 2. 不要在 `std::make_shared` 中传递裸指针:`std::make_shared` 是一个工厂函数,用于创建并初始化一个动态分配的对象,并返回一个指向该对象的 `std::shared_ptr`。为了避免意外泄漏资源,在使用 `std::make_shared` 时,应该直接传递构造参数而不是裸指针。例如,应该写成 `std::make_shared<T>(args...)` 而不是 `std::make_shared<T>(new T(args...))`。 3. 优先使用 `std::make_shared`:`std::make_shared` 可以在一次内存分配中同时分配对象和控制块(用于存储引用计数等信息)。这可以减少内存碎片并提高性能。所以,除非有特殊需求,推荐优先使用 `std::make_shared`。 4. 注意在多线程环境下的使用:`std::shared_ptr` 的引用计数是线程安全的,但对象的访问不是。在多线程环境下,需要考虑对象的并发访问问题,避免导致数据竞争和未定义行为。 5. 避免将不同的智能指针类型混合使用:`std::shared_ptr` 是一种线程安全的共享所有权的智能指针,而 `std::unique_ptr` 则是一种独占所有权的智能指针。将这两种不同类型的智能指针混合使用可能会导致问题,如编译错误或未定义行为。在需要共享所有权时,优先使用 `std::shared_ptr`。 总之,使用 `std::shared_ptr` 和 `std::make_shared` 可以帮助我们更方便地管理动态分配的内存资源,但在使用时需要注意上述事项以确保正确和高效地使用它们。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值