智能指针shared_ptr 的 reset使用

shared_ptr 的 reset() 有 4 个重载版本,如下:

void reset() noexcept; 							(1)	(since C++11)
template< class Y >
void reset( Y* ptr ); 							(2)	(since C++11)
template< class Y, class Deleter >
void reset( Y* ptr, Deleter d ); 				(3)	(since C++11)
template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc ); 	(4)	(since C++11)

常用到的应该是前 3 个版本,这里不举例第 4 个版本,因为我也没用过^_^ 

1,void reset() 版本

这个函数是最简单的,其作用:释放托管对象的所有权(如果有),调用后,该智能指针不再管理任何对象。注意,这里的释放并不是真正地去释放,只是引用计数减 1,而释放是引用计数为 0 时自行进行的。

#include <memory>
#include <iostream>
 
struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo::Foo(), bar = " << bar << " @ " << this << '\n';
    }
    ~Foo() {
        std::cout << "Foo::~Foo(), bar = " << bar << " @ " << this << "\n";
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};

void deleter(Foo *f)
{
    delete []f;
}


int main()
{
    std::cout << "1) unique ownership\n";
    {
        std::shared_ptr<Foo> sptr = std::make_shared<Foo>(100);
 
        std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
                  << sptr.use_count() << '\n';
 
        // Reset the shared_ptr without handing it a fresh instance of Foo.
        // The old instance will be destroyed after this call.
        std::cout << "call sptr.reset()...\n";
        sptr.reset(); // calls Foo's destructor here
        std::cout << "After reset(): use_count() = " << sptr.use_count()
                  << ", sptr = " << sptr << '\n';
    }   // No call to Foo's destructor, it was done earlier in reset().

    return 0;
}

可以看到在调用 reset() 后,调用了对象的析构函数进行释放。我们看 reset() 的另一种情况:

#include <memory>
#include <iostream>
 
struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo::Foo(), bar = " << bar << " @ " << this << '\n';
    }
    ~Foo() {
        std::cout << "Foo::~Foo(), bar = " << bar << " @ " << this << "\n";
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};


int main()
{
    std::cout << "1) unique ownership\n";
    {
        std::shared_ptr<Foo> sptr = std::make_shared<Foo>(100);
 
        std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
                  << sptr.use_count() << '\n';
 
        // Reset the shared_ptr without handing it a fresh instance of Foo.
        // The old instance will be destroyed after this call.
        std::cout << "call sptr.reset()...\n";
        sptr.reset(); // calls Foo's destructor here
        std::cout << "After reset(): use_count() = " << sptr.use_count()
                  << ", sptr = " << sptr << '\n';
    }   // No call to Foo's destructor, it was done earlier in reset().

    std::cout << "1) unique ownership\n";
    {
        std::shared_ptr<Foo> sptr = std::make_shared<Foo>(100);
 
        std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
                  << sptr.use_count() << '\n';

        std::shared_ptr<Foo> sptr1 = sptr;
        // Reset the shared_ptr without handing it a fresh instance of Foo.
        // The old instance will be destroyed after this call.
        std::cout << "call sptr1.reset()...\n";
        sptr1.reset(); // not calls Foo's destructor here
        std::cout << "After reset(): use_count() = " << sptr.use_count()
                  << ", sptr = " << sptr << '\n';
    }   // No call to Foo's destructor, it was done earlier in reset().
    return 0;
}

 

可以看到 Foo::bar = 100, use_count() = 2,此时两个智能指针都管理着 0x1029028 的资源,当调用 sptr1.reset(); 后,这个资源就少了一个管理者,所以 After reset(): use_count() = 1, sptr = 0x1029028,当离开作用域后,此资源才被释放。

2,模板版本带一个参数

template< class Y >
void reset( Y* ptr );  用ptr指向的对象替换托管对象

#include <memory>
#include <iostream>
 
struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo::Foo(), bar = " << bar << " @ " << this << '\n';
    }
    ~Foo() {
        std::cout << "Foo::~Foo(), bar = " << bar << " @ " << this << "\n";
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};

int main()
{
    std::cout << "\n1) unique ownership\n";
    {
        std::shared_ptr<Foo> sptr = std::make_shared<Foo>(200);
 
        std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
                  << sptr.use_count() << '\n';
 
        // Reset the shared_ptr, hand it a fresh instance of Foo.
        // The old instance will be destroyed after this call.
        std::cout << "call sptr.reset()...\n";
        sptr.reset(new Foo{222});
        std::cout << "After reset(): use_count() = " << sptr.use_count()
                  << ", sptr = " << sptr << "\nLeaving the scope...\n";
    }   // Calls Foo's destructor.

    return 0;
}

可以看到在  sptr.reset(new Foo{222}); 后,释放了 0x17d1028 指向的资源,当前指向的资源为 0x17d1040,离开作用域后自动释放。

3, 模板版本还两个参数

template<class Y, class Deleter>

void reset(Y *ptr, Deleter d)

带删除器的版本只会用在数组对象释放的情况,如果是数组对象的情况下不用删除器,则行为是未定义的。如:

#include <memory>
#include <iostream>
 
struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo::Foo(), bar = " << bar << " @ " << this << '\n';
    }
    ~Foo() {
        std::cout << "Foo::~Foo(), bar = " << bar << " @ " << this << "\n";
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};

int main()
{
    std::cout << "1) unique ownership\n";
    {
        std::shared_ptr<Foo> sptr = std::make_shared<Foo>(100);
 
        std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
                  << sptr.use_count() << '\n';
 
        // Reset the shared_ptr without handing it a fresh instance of Foo.
        // The old instance will be destroyed after this call.
        std::cout << "call sptr.reset()...\n";
        sptr.reset(new Foo[3]); // calls Foo's destructor here
        std::cout << "After reset(): use_count() = " << sptr.use_count()
                  << ", sptr = " << sptr << '\n';
    }   // No call to Foo's destructor, it was done earlier in reset().
 
    return 0;
}

正确用法可以是这样:

#include <memory>
#include <iostream>
 
struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo::Foo(), bar = " << bar << " @ " << this << '\n';
    }
    ~Foo() {
        std::cout << "Foo::~Foo(), bar = " << bar << " @ " << this << "\n";
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};

void customDeleter(Foo *f)
{
    if(f)
    {
        delete []f;
    }
}

int main()
{
    std::cout << "1) unique ownership\n";
    {
        std::shared_ptr<Foo> sptr = std::make_shared<Foo>(100);
 
        std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
                  << sptr.use_count() << '\n';
 
        // Reset the shared_ptr without handing it a fresh instance of Foo.
        // The old instance will be destroyed after this call.
        std::cout << "call sptr.reset()...\n";
        sptr.reset(new Foo[3], customDeleter); // calls Foo's destructor here
        std::cout << "After reset(): use_count() = " << sptr.use_count()
                  << ", sptr = " << sptr << '\n';
    }   // No call to Foo's destructor, it was done earlier in reset().
 
    return 0;
}

 添加删除函数:

void customDeleter(Foo *f)
{
    if(f)
    {
        delete []f;
    }
}

reset 调用时指定删除器: sptr.reset(new Foo[3], customDeleter);

因为只有释放数组对象时才需要指定删除器,所以实现就是 delete [],我们看结果:

最后调用的 3 个析构函数。

还可以使用 std::default_delete 模板,如:sptr.reset(new Foo[3], std::default_delete<Foo[]>());

#include <memory>
#include <iostream>
 
struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo::Foo(), bar = " << bar << " @ " << this << '\n';
    }
    ~Foo() {
        std::cout << "Foo::~Foo(), bar = " << bar << " @ " << this << "\n";
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};


int main()
{
    std::cout << "1) unique ownership\n";
    {
        std::shared_ptr<Foo> sptr = std::make_shared<Foo>(100);
 
        std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
                  << sptr.use_count() << '\n';
 
        // Reset the shared_ptr without handing it a fresh instance of Foo.
        // The old instance will be destroyed after this call.
        std::cout << "call sptr.reset()...\n";
      
        sptr.reset(new Foo[3], std::default_delete<Foo[]>());
        std::cout << "After reset(): use_count() = " << sptr.use_count()
                  << ", sptr = " << sptr << '\n';
    }   // No call to Foo's destructor, it was done earlier in reset().
 
    return 0;
}

 

同样释放正常。

<think>好的,我现在需要回答用户关于C++shared_ptr使用方法及示例的问题。首先,我应该回忆一下自己对shared_ptr的了解,并结合提供的引用资料来确保信息的准确性。 首先,shared_ptrC++智能指针的一种,用于自动管理动态分配的内存,防止内存泄漏。根据引用1,shared_ptr采用引用计数机制,多个shared_ptr可以共享同一个对象,当最后一个shared_ptr被销毁时,对象才会被释放。引用2提到shared_ptr允许拷贝和赋值,这说明它们支持共享所有权。引用3则补充了shared_ptr销毁对象的条件,即最后一个拥有对象的shared_ptr被销毁或重置时。 接下来,我需要组织回答的结构。用户需要使用方法及示例,所以应该分步骤讲解,并附上代码示例。可能的要点包括:创建shared_ptr、共享所有权、自定义删除器、注意事项等。 创建shared_ptr部分,需要说明如何用make_shared或直接构造。共享所有权要展示多个指针指向同一对象的情况。自定义删除器可以举文件关闭的例子。注意事项要提到循环引用的问题,并引入weak_ptr作为解决方案。 在写代码示例时,要确保语法正确,并且每段代码有注释解释。同时,要引用提供的资料中的信息,比如在说明引用计数时引用[^1],在提到拷贝赋值时引用[^2],在销毁条件时引用[^3]。 另外,用户的问题可能涉及相关技术问题,比如循环引用,所以需要解释问题原因和解决方法。这里需要提到weak_ptr,并给出示例,如引用3中提到的weak_ptr用于打破循环。 最后,生成相关问题时要围绕shared_ptr的扩展内容,比如与unique_ptr的区别、循环引用的解决、性能分析等。 需要检查是否符合用户的要求:使用中文、正确格式的数学公式(如果有的话)、引用标识、代码块格式正确。但在这个问题中可能没有数学公式,但如果有涉及计算的地方,需要按格式处理。 总结回答的结构: 1. shared_ptr基本概念和引用计数机制 2. 创建方法(make_shared) 3. 共享所有权示例 4. 自定义删除器 5. 注意事项(循环引用和weak_ptr) 6. 示例代码 7. 相关问题 确保每个部分都简洁明了,引用正确的资料,示例代码正确无误。</think>### C++ shared_ptr 使用方法及示例 #### 1. shared_ptr 基本概念 `shared_ptr` 是 C++ 标准库提供的智能指针,通过**引用计数机制**管理动态分配的内存。多个 `shared_ptr` 可以指向同一对象,当最后一个 `shared_ptr` 被销毁或重置时,对象内存会被自动释放[^1]。 --- #### 2. 使用方法 ##### (1) 创建 shared_ptr 推荐使用 `std::make_shared` 创建,既安全又高效: ```cpp #include <memory> // 创建指向 int 的 shared_ptr auto sp1 = std::make_shared<int>(42); // 直接构造(不推荐,可能引发异常安全问题) std::shared_ptr<int> sp2(new int(100)); ``` ##### (2) 共享所有权 多个 `shared_ptr` 可以共享同一对象,引用计数自动增加/减少: ```cpp auto sp3 = sp1; // 引用计数变为2 sp3.reset(); // 引用计数恢复为1 ``` ##### (3) 自定义删除器 默认删除器调用 `delete`,但可自定义(如用于文件句柄): ```cpp std::shared_ptr<FILE> file_ptr( fopen("test.txt", "r"), [](FILE* f) { if (f) fclose(f); } ); ``` --- #### 3. 注意事项 ##### 循环引用问题 若两个 `shared_ptr` 互相引用,会导致内存泄漏。需用 `weak_ptr` 打破循环: ```cpp class B; // 前向声明 class A { public: std::shared_ptr<B> b_ptr; }; class B { public: std::weak_ptr<A> a_weak_ptr; // 使用 weak_ptr 避免循环引用 }; ``` --- #### 4. 完整示例 ```cpp #include <iostream> #include <memory> struct Data { Data() { std::cout << "Data created\n"; } ~Data() { std::cout << "Data destroyed\n"; } }; int main() { // 创建 shared_ptr auto d1 = std::make_shared<Data>(); { auto d2 = d1; // 引用计数变为2 std::cout << "d2 使用中,引用计数=" << d2.use_count() << "\n"; } // d2 销毁,引用计数恢复为1 std::cout << "d1 引用计数=" << d1.use_count() << "\n"; return 0; } ``` **输出**: ``` Data created d2 使用中,引用计数=2 d1 引用计数=1 Data destroyed ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值