共享指针(shared_ptr)对于类的拷贝/赋值带来的好处

1.不使用共享指针的情况

#include <iostream>
#include <memory>
#include <string.h>

class A{
    public:
        A() {
            std::cout << "create A." << std::endl;
        }

        A(A& a) {
            std::cout << "copy create A." << std::endl;
        }

        ~A() {
            std::cout << "destroy A." << std::endl;
        }

    private:
};

class B {
    public:
        B() : a_ptr_(new A()){
            std::cout << "create B." << std::endl;
        }

        B(B& b) {
            std::cout << "copy create B." << std::endl;
            //a_ptr_ = new A();
            //memcpy(a_ptr_, b.a_ptr_, sizeof(A));
            a_ptr_ = new A(*b.a_ptr_);
        }

        B& operator=(const B& b) {
            std::cout << "copy assignment B." << std::endl;
            if(a_ptr_ != nullptr)
                delete a_ptr_;

            a_ptr_ = new A(*b.a_ptr_);
            return *this;
        }

        ~B() {
            delete a_ptr_;
            std::cout << "destroy B." << std::endl;
        }

    private:
        //std::shared_ptr<A> a_ptr_;
        A* a_ptr_;
};

int main() {
    std::cout << "***b1***" << std::endl;
    B b1;

    std::cout << "***b2 copy construct: b2=b1***" << std::endl;
    {
        B b2=b1;
    }

    std::cout << "***b3 copy assignment: b3=b1***" << std::endl;
    {
        B b3;
        std::cout << "---split---" << std::endl;
        b3 = b1;
    }
    std::cout << "---end of main---" << std::endl;
}

执行结果:

***b1***
create A.
create B.
***b2 copy construct: b2=b1***
copy create B.
copy create A.
destroy A.
destroy B.
***b3 copy assignment: b3=b1***
create A.
create B.
---split---
copy assignment B.
destroy A.
copy create A.
destroy A.
destroy B.
---end of main---
destroy A.
destroy B.
  1. 使用共享指针的情况1(这种是有问题的)
#include <iostream>
#include <memory>

class A{
    public:
        A() {
            std::cout << "create A." << std::endl;
        }

        ~A() {
            std::cout << "destroy A." << std::endl;
        }

    private:
};

class B {
    public:
        B() {
            std::cout << "create B." << std::endl;
            a_ptr_ = std::make_shared<A>();
        }

        B(B& b) : a_ptr_(b.a_ptr_) {
            std::cout << "copy create B." << std::endl;
        }

        B& operator=(const B& b) {
            std::cout << "copy create B." << std::endl;
            a_ptr_ = b.a_ptr_;
            return *this;
        }

        ~B() {
            std::cout << "destroy B." << std::endl;
        }

    private:
        std::shared_ptr<A> a_ptr_;
};


int main() {
    std::cout << "***b1***" << std::endl;
    B b1;

    std::cout << "***b2 copy construct: b2=b1***" << std::endl;
    {
        B b2=b1;
    }

    std::cout << "***b3 copy assignment: b3=b1***" << std::endl;
    {
        B b3;
        std::cout << "---split---" << std::endl;
        b3 = b1;
    }
    std::cout << "---end of main---" << std::endl;
}

执行结果:

***b1***
create B.
create A.
***b2 copy construct: b2=b1***
copy create B.
destroy B.
***b3 copy assignment: b3=b1***
create B.
create A.
---split---
copy create B.
destroy A.
destroy B.
---end of main---
destroy B.
destroy A.

注意:
  这里类B中的成员函数是类A的共享指针,即使我们没有写自定义的拷贝构造和拷贝复制函数,程序也不会崩溃,但是在使用普通的类A的指针时,程序是会崩溃的.
  但是这里有一个新问题:因为在拷贝构造和复制函数中只是对共享指针进行了简单赋值,也就是说它们指向的是同一块内存.当修改复制出来的类对象中的a_ptr_时,被复制的类对象中的a_ptr_也被修改;
  
2.1 当修改复制出来的类对象中的a_ptr_时,被复制的类对象中的a_ptr_也被修改;

#include <iostream>
#include <memory>

class A{
    public:
        A():m_(100) {
            std::cout << "create A." << std::endl;
        }

        ~A() {
            std::cout << "destroy A." << std::endl;
        }

        void set_m(int value) {
            m_ = value;
        }

        int get_m() {
            return m_;
        }

    private:
        int m_;
};

class B {
    public:
        B() {
            std::cout << "create B." << std::endl;
            a_ptr_ = std::make_shared<A>();
        }

        B(B& b) : a_ptr_(b.a_ptr_) {
            std::cout << "copy create B." << std::endl;
        }

        ~B() {
            std::cout << "destroy B." << std::endl;
        }

        void reset_a() {
            a_ptr_ = std::make_shared<A>();
        }

        void print_a_address() {
            std::cout << "address of a_ptr_ pointed to: " << a_ptr_.get() << std::endl;
        }

        void change_a(int value) {
            a_ptr_->set_m(value);
        }

        void print_a() {
            std::cout << a_ptr_->get_m() << std::endl;
        }

    private:
        std::shared_ptr<A> a_ptr_;
};


int main() {
    std::cout << "***b1***" << std::endl;
    B b1;

    std::cout << "***b2 copy construct: b2=b1***" << std::endl;
    {
        B b2=b1;
        b1.print_a();
        b2.print_a();
        b2.change_a(200);
        b1.print_a();
        b2.print_a();
    }

    std::cout << "---end of main---" << std::endl;
}

执行结果:

***b1***
create B.
create A.
***b2 copy construct: b2=b1***
copy create B.
100
100
200
200
destroy B.
---end of main---
destroy B.
destroy A.

可以看出:修改了b2中的a_ptr_的值以后,b1中的a_ptr_的值也被改变了.

2.2 如果在类对象b2中重新创建a_ptr_对象,则不会出现2.1中的问题;

#include <iostream>
#include <memory>

class A{
    public:
        A():m_(100) {
            std::cout << "create A." << std::endl;  
        }

        ~A() {
            std::cout << "destroy A." << std::endl; 
        }

        void set_m(int value) {
            m_ = value;
        }
    
        int get_m() {
            return m_; 
        }

    private:
        int m_; 
};

class B { 
    public:
        B() {
            std::cout << "create B." << std::endl;  
            a_ptr_ = std::make_shared<A>();
        }

        B(B& b) : a_ptr_(b.a_ptr_) {
            std::cout << "copy create B." << std::endl; 
        }
    
        ~B() {
            std::cout << "destroy B." << std::endl; 
        }

        void reset_a() {
            a_ptr_ = std::make_shared<A>();
        }
    
        void print_a_address() {
            std::cout << "address of a_ptr_ pointed to: " << a_ptr_.get() << std::endl;
        }

        void change_a(int value) {
            a_ptr_->set_m(value);
        }

        void print_a() {
            std::cout << a_ptr_->get_m() << std::endl;
        }
        
    private:
        std::shared_ptr<A> a_ptr_;
};


int main() {
    std::cout << "***b1***" << std::endl;
    B b1; 

    std::cout << "***b2 copy construct: b2=b1***" << std::endl;
    {   
        B b2=b1;
        b1.print_a();
        b2.print_a();
        b2.reset_a();
        b2.change_a(200);
        b1.print_a();
        b2.print_a();
    }   

    std::cout << "---end of main---" << std::endl;
}

执行:

***b1***
create B.
create A.
***b2 copy construct: b2=b1***
copy create B.
100
100
create A.
100
200
destroy B.
destroy A.
---end of main---
destroy B.
destroy A.

因此,使用共享指针虽然可以避免程序crash, 但是还是要手动对共享指针赋值,才能保证对象之间的内存的绝对分离,保证使用安全.

  1. 使用共享指针的情况2
#include <iostream>
#include <memory>
#include <string.h>

class A{
    public:
        A():m_(100) {
            std::cout << "create A." << std::endl;
        }

        ~A() {
            std::cout << "destroy A." << std::endl;
        }

        void set_m(int value) {
            m_ = value;
        }

        int get_m() {
            return m_;
        }

    private:
        int m_;
};

class B {
    public:
        B() {
            std::cout << "create B." << std::endl;
            a_ptr_ = std::make_shared<A>();
        }

        /*B(B& b) : a_ptr_(std::make_shared<A>()) {
            std::cout << "copy create B." << std::endl; 
            memcpy(a_ptr_.get(), b.a_ptr_.get(), sizeof(A));
        }*/

        B(B& b) : a_ptr_(new A()) {
            std::cout << "copy create B." << std::endl;
            memcpy(a_ptr_.get(), b.a_ptr_.get(), sizeof(A));
        }

        B& operator=(const B& b) {
            std::cout << "copy create B." << std::endl;
            a_ptr_ = std::make_shared<A>();
            memcpy(a_ptr_.get(), b.a_ptr_.get(), sizeof(A));
            return *this;
        }

        ~B() {
            std::cout << "destroy B." << std::endl;
        }

        void reset_a() {
            a_ptr_ = std::make_shared<A>();
        }

        void print_a_address() {
            std::cout << "address of a_ptr_ pointed to: " << a_ptr_.get() << std::endl;
        }

        void change_a(int value) {
            a_ptr_->set_m(value);
        }

        void print_a() {
            std::cout << a_ptr_->get_m() << std::endl;
        }

    private:
        std::shared_ptr<A> a_ptr_;
};


int main() {
    std::cout << "***b1***" << std::endl;
    B b1;

    std::cout << "***b2 copy construct: b2=b1***" << std::endl;
    {
        B b2=b1;
        b1.print_a();
        b2.print_a();
        b2.change_a(200);
        b1.print_a();
        b2.print_a();
    }

    std::cout << "***b3 copy assignment: b3=b1***" << std::endl;
    {
        B b3;
        std::cout << "---split---" << std::endl;
        b3 = b1;
    }
    std::cout << "---end of main---" << std::endl;
}

***b1***
create B.
create A.
***b2 copy construct: b2=b1***
create A.
copy create B.
100
100
100
200
destroy B.
destroy A.
***b3 copy assignment: b3=b1***
create B.
create A.
---split---
copy create B.
create A.
destroy A.
destroy B.
destroy A.
---end of main---
destroy B.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智能指针 智能指针shared_ptr的⽤法 的⽤法   为了解决C++内存泄漏的问题,C++11引⼊了智能指针(Smart Pointer)。   智能指针的原理是,接受⼀个申请好的内存地址,构造⼀个保存在栈上的智能指针对象,当程序退出栈的作⽤域范围后,由于栈上的变 量⾃动被销毁,智能指针内部保存的内存也就被释放掉了(除⾮将智能指针保存起来)。   C++11提供了三种智能指针:std::shared_ptr, std::unique_ptr, std::weak_ptr,使⽤时需添加头⽂件<memory>。   shared_ptr使⽤引⽤计数,每⼀个shared_ptr拷贝都指向相同的内存。每使⽤他⼀次,内部的引⽤计数加1,每析构⼀次,内部的引⽤ 计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引⽤计数是安全的,但是对象的读取需要加锁。 1. shared_ptr的基本⽤法 初始化   可以通过构造函数、std::make_shared<T>辅助函数和reset⽅法来初始化shared_ptr: #include "stdafx.h" #include <iostream> #include <future> #include <thread> using namespace std; class Person { public: Person(int v) { value = v; std::cout << "Cons" <<value<< std::endl; } ~Person() { std::cout << "Des" <<value<< std::endl; } int value; }; int main() { std::shared_ptr<Person> p1(new Person(1));// Person(1)的引⽤计数为1 std::shared_ptr<Person> p2 = std::make_shared<Person>(2); p1.reset(new Person(3));// ⾸先⽣成新对象,然后引⽤计数减1,引⽤计数为0,故析构Person(1) // 最后将新对象的指针交给智能指针 std::shared_ptr<Person> p3 = p1;//现在p1和p3同时指向Person(3),Person(3)的引⽤计数为2 p1.reset();//Person(3)的引⽤计数为1 p3.reset();//Person(3)的引⽤计数为0,析构Person(3) return 0; }   注意,不能将⼀个原始指针直接赋值给⼀个智能指针,如下所⽰,原因是⼀个是,⼀个是指针。 std::shared_ptr<int> p4 = new int(1);// error   reset()包含两个操作。当智能指针中有值的时候,调⽤reset()会使引⽤计数减1.当调⽤reset(new xxx())重新赋值时,智能指针⾸先是⽣ 成新对象,然后将就对象的引⽤计数减1(当然,如果发现引⽤计数为0时,则析构旧对象),然后将新对象的指针交给智能指针保管。 获取原始指针   std::shared_ptr<int> p4(new int(5)); int *pInt = p4.get(); 指定删除器   智能指针可以指定删除器,当智能指针的引⽤计数为0时,⾃动调⽤指定的删除器来释放内存。std::shared_ptr可以指定删除器的⼀个原 因是其默认删除器不⽀持数组对象,这⼀点需要注意。   2. 使⽤shared_ptr需要注意的问题   但凡⼀些⾼级的⽤法,使⽤时都有不少陷阱。 不要⽤⼀个原始指针初始化多个shared_ptr,原因在于,会造成⼆次销毁,如下所⽰: int *p5 = new int; std::shared_ptr<int> p6(p5); std::shared_ptr<int> p7(p5);// logic error 不要在函数实参中创建shared_ptr。因为C++的函数参数的计算顺序在不同的编译器下是不同的。正确的做法是先创建好,然后再传 ⼊。 function(shared_ptr<int>(new int), g()); 禁⽌通过shared_from_this()返回this指针,这样做可能也会造成⼆次析构。 避免循环引⽤。智能指针最⼤的⼀个陷阱是循环引⽤,循环引⽤会导致内存泄漏。解决⽅法是AStruct或BStruct改为weak_ptr。 struct AStruct; struct BStruct; struct AStruct { std::shared_ptr<BStruct> bPtr; ~AStruct() {
C++智能指针shared_ptr讲解与使⽤ ⼿动管理的弊端 在简单的程序中,我们不⼤可能忘记释放 new 出来的指针,但是随着程序规模的增⼤,我们忘了 delete 的概率也随之增⼤。在 C++ 中 new 出来的指针赋值意味着引⽤的传递,当赋值运算符同时展现出"值拷贝"和"引⽤传递"两种截然不同的语义时,就很容易导致"内 存泄漏"。 ⼿动管理内存带来的更严重的问题是,内存究竟要由谁来分配和释放呢?指针赋值将同⼀对象的引⽤散播到程序各处,但是该对象的释放 却只能发⽣⼀次。当在代码中⽤完了⼀个资源指针,该不该释放 delete 掉它?这个资源极有可能同时被多个对象拥有着,⽽这些对象中的 任何⼀个都有可能在之后使⽤该资源,其余指向这个对象的指针就变成了"野指针";那如果不 delete 呢?也许你就是这个资源指针的唯 ⼀使⽤者,如果你⽤完不 delete,内存就泄漏了。 资源的拥有者是系统,当我们需要时便向系统申请资源,当我们不需要时就让系统⾃⼰收回去(Garbage Collection)。当我们⾃⼰处理的时 候,就容易出现各种各样的问题。 C++中的智能指针C++11起,C++标准提供两⼤型的智能指针: 1. Class shared_ptr实现共享式拥有(shared ownership)概念。多个智能指针可以指向相同对象,该对象和其相关资源会在"最后⼀个引 ⽤(reference)被销毁"时候释放。为了在结构复杂的情境中执⾏上述⼯作,标准库提供了weak_ptr、bad_weak_ptr和 enable_shared_from_this等辅助。 2. Class unique_ptr实现独占式拥有(exclusive ownership)或严格拥有(strict ownership)概念,保证同⼀时间内只有⼀个智能指针 可以指向该对象。它对于避免资源泄露(resourece leak)——例如"以new创建对象后因为发⽣异常⽽忘记调⽤delete"——特别有⽤。 注:C++98中的Class auto_ptrC++11中已不再建议使⽤。 share_ptr 智能指针是(⼏乎总是)模板shared_ptr 同样是模板,所以在创建 shared_ptr 时需要指定其指向的型。shared_ptr 负责在不使 ⽤实例时释放由它管理的对象,同时它可以⾃由的共享它指向的对象。 shared_ptr 使⽤经典的 "引⽤计数" 的⽅法来管理对象资源。引⽤计数指的是,所有管理同⼀个裸指针( raw pointer )的 shared_ptr,都共享⼀个引⽤计数器,每当⼀个 shared_ptr赋值(或拷贝构造)给其它 shared_ptr 时,这个共享的引⽤计数器就加 1,当⼀个 shared_ptr 析构或者被⽤于管理其它裸指针时,这个引⽤计数器就减1,如果此时发现引⽤计数器为0,那么说明它是管理这个 指针的最后⼀个 shared_ptr 了,于是我们释放指针指向的资源。 在底层实现中,这个引⽤计数器保存在某个内部型⾥(这个型中还包含了 deleter,它控制了指针的释放策略,默认情况下就是普通的 delete操作),⽽这个内部型对象在 shared_ptr 第⼀次构造时以指针的形式保存在 shared_ptr 中(所以⼀个智能指针的析构会影响到 其他指向同⼀位置的智能指针)。shared_ptr 重载了赋值运算符,在赋值拷贝构造另⼀个 shared_ptr 时,这个指针被另⼀个 shared_ptr 共享。在引⽤计数归零时,这个内部指针shared_ptr 管理的资源⼀起被释放。此外,为了保证线程安全性,引⽤计数 器的加1,减1操作都是 原⼦操作,它保证 shared_ptr 由多个线程共享时不会爆掉。 对于 shared_ptr拷贝赋值时的⾏为,《C++Primer第五版》中有详细的描述: 每个 shared_ptr 都有⼀个关联的计数值,通常称为引⽤计数。⽆论何时我们拷贝⼀个 shared_ptr,计数器都会递增。 例如,当⽤⼀个 shared_ptr 初始化另⼀个 shred_ptr,或将它当做参数传递给⼀个函数以及作为函数的返回值时,它所关联的计数 器就会递增。当我们给 shared_ptr 赋予⼀个新值或是 shared_ptr 被销毁(例如⼀个局部的 shared_ptr 离开其作⽤域)时,计数 器就会递减。⼀旦⼀个 shared_ptr 的计数器变为0,它就会⾃动释放⾃⼰所管理的对象。 下⾯看⼀个常见⽤法,包括: 1. 创建 shared_ptr 实例 2. 访问所指对象 3. 拷贝赋值操作 4. 检查引⽤计数。 #include <iostream> #include
C++智能指针 智能指针_unique_ptr智能指针详解 智能指针详解 作为智能指针的⼀种,unique_ptr 指针⾃然也具备"在适当时机⾃动释放堆内存空间"的能⼒。和 shared_ptr 指针最⼤的不同之处在 于,unique_ptr 指针指向的堆内存⽆法同其它 unique_ptr 共享,也就是说,每个 unique_ptr 指针都独⾃拥有对其所指堆内存空间的所有 权。 这也就意味着,每个 unique_ptr 指针指向的堆内存空间的引⽤计数,都只能为 1,⼀旦该 unique_ptr 指针放弃对所指堆内存空 间的所有权,则该空间会被⽴即释放回收。 unique_ptr 智能指针是以模板的形式提供的,unique_ptr<T>(T 为指针所指数据的型)定义在<memory>头⽂件,并位于 std 命名空间 中。因此,要想使⽤ unique_ptr 指针,程序中应⾸先包含如下 2 条语句: 1. #include <memory> 2. using namespace std; 第 2 句并不是必须的,可以不添加,则后续在使⽤ unique_ptr 指针时,必须标注std:: 。 unique_ptr智能指针的创建 智能指针的创建 考虑到不同实际场景的需要,unique_ptr<T> 模板提供了多个实⽤的构造函数,这⾥给读者列举了⼏种常⽤的构造 unique_ptr 智能指针的⽅式。 1) 通过以下 2 种⽅式,可以创建出空的 unique_ptr 指针: 1. std::unique_ptr<int> p1(); 2. std::unique_ptr<int> p2(nullptr); 2) 创建 unique_ptr 指针的同时,也可以明确其指向。例如: 1. std::unique_ptr<int> p3(new int); 由此就创建出了⼀个 p3 智能指针,其指向的是可容纳 1 个整数的堆存储空间。 和可以⽤ make_shared<T>() 模板函数初始化 shared_ptr 指针不同,C++11 标准中并没有为 unique_ptr 指针添 加似的模板函数。 3) 基于 unique_ptr 指针共享各⾃拥有的堆内存,因此 C++11 标准中的 unique_ptr 模板没有提供拷贝构造函数,只提供 了移动构造函数。例如: 1. std::unique_ptr<int> p4(new int); 2. std::unique_ptr<int> p5(p4);//错误,堆内存不共享 3. std::unique_ptr<int> p5(std::move(p4));//正确,调⽤移动构造函数 值得⼀提的是,对于调⽤移动构造函数的 p4 和 p5 来说,p5 将获取 p4 所指堆空间的所有权,⽽ p4 将变成空指针(nullptr)。 4) 默认情况下,unique_ptr 指针采⽤ std::default_delete<T> ⽅法释放堆内存。当然,我们也可以⾃定义符合实际场景的释放规 则。值得⼀提的是,和 shared_ptr 指针不同,为 unique_ptr ⾃定义释放规则,只能采⽤函数对象的⽅式。例如: 1. //⾃定义的释放规则 2. struct myDel 3. { 4. void operator()(int *p) { 5. delete p; 6. } 7. }; 8. std::unique_ptr<int, myDel> p6(new int); 9. //std::unique_ptr<int, myDel> p6(new int, myDel()); unique_ptr<T>模板提供的成员⽅法 模板提供的成员⽅法 为了⽅便⽤户使⽤ unique_ptr 智能指针,unique_ptr<T> 模板还提供有⼀些实⽤的成员⽅法,它们各⾃的功能如表 1 所⽰。 表 1 unique_ptr指针可调⽤的成员函数 成员函数名 成员函数名 功 功 能 能 operator*() 获取当前 unique_ptr 指针指向的数据。 operator->() 重载 -> 号,当智能指针指向的数据型为⾃定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。 operator =() 重载了 = 赋值号,从⽽可以将 nullptr 或者⼀个右值 unique_ptr 指针直接赋值给当前同型的 unique_ptr 指针。 operator []() 重载了 [] 运算符,当 unique_ptr 指针指向⼀个数组时,可以直接通过 [] 获取指定下标位置处的数据。 get() 获取当前 unique_ptr 指针内部包含的普通指针。 get_deleter()
C++智能指针shared_ptr⽤法详解 C++智能指针shared_ptr⽤法详解 shared_ptrC++11⾥的新特性,其包装了new操作符在堆上分配的动态对象。如: shared_ptr<int> sp1(new int(100)); //相当于 //int *sp1=new int(100); //auto sp1=make_shared<int>(100); 它与普通指针相⽐,最⼤的不同点就是shared_ptr是⼀个,当对象⽣命周期结束时,会⾃动调⽤其析构函数,释放内存。⽽不再需要程 序员显⽰地调⽤delete关键字。 同时,shared_ptr重载了"*"和"->"操作符以模仿原始指针的⾏为,并且提供了显⽰bool型转换以判断指针的有效性。 shared_ptr<int> sp1(new int(100)); assert(sp1); *sp1=200; shared_ptr<string> sp2(new string("Hello")); assert(sp2->size()==5); 我们还可以使⽤shared_ptr的成员函数get()获取原始指针 shared_ptr<int> sp1(new int(100)); int *Int_ptr=sp1.get(); shared_ptr⾥的reset()函数 shared_ptr⾥有个成员函数use_count(),⽤于返回该对象的引⽤计数。 shared_ptr<int> sp1(new int(100)); cout<<"当前计数: "<<sp1.use_count()<<endl; auto sp2=sp1; cout<<"当前计数: "<<sp1.use_count()<<endl; { auto sp3=sp2; cout<<"当前计数: "<<sp1.use_count()<<endl; } cout<<"当前计数: "<<sp1.use_count()<<endl; 当⼀个shared_ptr对象调⽤reset()函数时,它的作⽤时将引⽤计数减⼀,调⽤本⾝的对象的引⽤计数变为0. shared_ptr<int> sp1(new int(100)); cout<<"当前计数: "<<sp1.use_count()<<endl; auto sp2=sp1; cout<<"当前计数: "<<sp1.use_count()<<endl; { auto sp3=sp2; cout<<"当前计数: "<<sp1.use_count()<<endl; } cout<<"当前计数: "<<sp1.use_count()<<endl; sp2.reset();//这⾥换成sp1.reset(),可以发现sp2的计数为1,sp1的计数为0. cout << "sp2当前计数: " << sp2.use_count() << endl; cout << "sp1当前计数: " << sp2.use_count() << endl; 上⾯代码运⾏后,sp2的计数为0,sp1的计数为1。若将sp2.reset()换位sp1.reset(),则sp2的计数为1,sp1的计数为0。 在每次对shared_ptr进⾏拷贝或者赋值的时候,都会使计数加1。 ⼯⼚函数 每次使⽤shared_ptr都需要显⽰的使⽤new关键字创建⼀个对象。固std库提供了⼀个⼯⼚函数make_shared()。 ⽤法: auto sp1=make_shared<int>(100); //相当于 shared_ptr<int> sp1(new int(100)); make_shared是⼀个泛型,<>⾥⾯为数据型,()对应着new()⾥的东西,其返回值是⼀个shared_ptr型的变量。 定制删除器 shared_ptr的构造函数可有多个参数,其中有⼀个是shared_ptr(Y *p,D d),第⼀个参数是要被管理的指针,它的含义与其构造函数的参 数相同。⽽第⼆个参数则告诉shared_ptr在析构时不要使⽤delete来操作指针p,⽽要⽤d来操作,即把delete p 换成d(p)。因此,我们 就可以⾃⼰制作⼀个删除器 如:对于传统的struct FILE的C⽂件操作,需要 FILE *fp=fopen("./1.txt","r"); //... //... fclose(fp); 若⽤shared_ptr,则可以这样做: shared_ptr<FILE> fp(fopen("./1.txt","r"), fclose); 离开作⽤域时,shared_ptr会⾃动调⽤fclose()函数关闭⽂件。
智能指针shared_ptr的代码实现如下: ```cpp template <typename T> class shared_ptr { public: // 构造函数 explicit shared_ptr(T* ptr = nullptr) : ptr_(ptr), count_(nullptr) { if (ptr_) { count_ = new size_t(1); } } // 拷贝构造函数 shared_ptr(const shared_ptr<T>& other) : ptr_(other.ptr_), count_(other.count_) { if (count_) { (*count_)++; } } // 移动构造函数 shared_ptr(shared_ptr<T>&& other) noexcept : ptr_(other.ptr_), count_(other.count_) { other.ptr_ = nullptr; other.count_ = nullptr; } // 析构函数 ~shared_ptr() { if (count_) { (*count_)--; if (*count_ == 0) { delete ptr_; delete count_; } } } // 重载赋值运算符 shared_ptr<T>& operator=(const shared_ptr<T>& other) { if (this != &other) { shared_ptr<T> temp(other); swap(temp); } return *this; } // 获取指针所指向的对象 T* get() const { return ptr_; } // 重载箭头运算符 T* operator->() const { return ptr_; } // 重载解引用运算符 T& operator*() const { return *ptr_; } // 获取引用计数 size_t use_count() const { if (count_) { return *count_; } else { return 0; } } // 交换两个智能指针的内容 void swap(shared_ptr<T>& other) { std::swap(ptr_, other.ptr_); std::swap(count_, other.count_); } private: T* ptr_; // 指向实际对象的指针 size_t* count_; // 引用计数 }; ``` 这是一个简单的shared_ptr实现,它包含了构造函数、拷贝构造函数、移动构造函数、析构函数、赋值运算符重载、获取指针、箭头运算符重载、解引用运算符重载、获取引用计数和交换指针内容等功能。通过引用计数来跟踪指针被多少个shared_ptr共享,并在最后一个shared_ptr析构时删除实际对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值