C++中的智能指针

博客主要围绕C++智能指针展开,分析了智能指针拷贝情况,如对智能指针pNico的拷贝是浅拷贝,改变对象值时指向它的指针都会指向新值;还提到指向对象“Jutta”的指针数量及use_count值。此外,介绍了shared_ptr默认内存释放器,指出其对数组内存空间需自定义释放器,并给出相关资料链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用法

#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

int main(void)
{
    // two shared pointers representing two persons by their name
    shared_ptr<string> pNico(new string("nico"));
    // 自定义析构函数,只是为了展示,实际情况使用默认的就可以了
    shared_ptr<string> pJutta(new string("jutta"),
            // deleter (a lambda function) 
            [](string *p)
            { 
                cout << "delete " << *p << endl;
                delete p;
            }
        );

    // 获得指向对象(*pNico)
    // capitalize person names
    (*pNico)[0] = 'N';
    // ->调用类String的函数replace
    pJutta->replace(0, 1, "J");

    // put them multiple times in a container
    vector<shared_ptr<string> > whoMadeCoffee;
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pNico);
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pNico);

    // print all elements
    for (auto ptr : whoMadeCoffee)
        cout << *ptr << " ";
    cout << endl;

    // overwrite a name again
    *pNico = "Nicolai";

    // print all elements
    for (auto ptr : whoMadeCoffee)
        cout << *ptr << " ";
    cout << endl;

    // print some internal data
    cout << "use_count: " << whoMadeCoffee[0].use_count() << endl;

    return 0;
}

结果:

Jutta Jutta Nico Jutta Nico
Jutta Jutta Nicolai Jutta Nicolai
use_count: 4
delete Jutta

分析:
这里写图片描述
1. 对智能指针pNico的拷贝是浅拷贝,所以当我们改变对象“Nico”的值为“Nicolai”时,指向它的指针都会指向新值。
2. 指向对象“Jutta”的有四个指针:pJuttapJutta的三份被安插到容器内的拷贝,所以上述程序输出的use_count为4。
3. shared_ptr本身提供默认内存释放器(default deleter),调用的是delete,不过只对“由new建立起来的单一对象”起作用。当然我们也可以自己定义内存释放器,就如上述程序。不过值得注意的是,默认内存释放器并不能释放数组内存空间,而是要我们自己提供内存释放器,如:

shared_ptr<int> p(new int[10], default_delete<int[]>());

或者

shared_ptr<int> pJutta2(new int[10],
        // deleter (a lambda function) 
        [](int *p)
        { 
            delete[] p;
        }
    );

很好的资料

http://www.cnblogs.com/lanxuezaipiao/p/4132096.html

实现

#include <iostream>
using namespace std;

template<class T>
class SharedPtr {
public:
    SharedPtr(T *p);
    ~SharedPtr();
    // 拷贝构造函数
    SharedPtr(const SharedPtr<T> &orig);
    // =重载 
    SharedPtr<T>& operator=(const SharedPtr<T> &rhs);
private:
    T *ptr;
    int *use_count;     
};

template<class T>
SharedPtr<T>::SharedPtr(T *p) : ptr(p) {
    try {
        assert(p!=nullptr);
        use_count = new int(1);
    } 
    catch (...) {
        if(p==nullptr) 
            cout<<"Init with nullptr"<<endl;
        else {
            delete ptr;
            use_count = nullptr;
            cout<<"Allocate memory for use_count fails."<<endl;
        }
        exit(1);

    }
    cout<<"Constructor is called!"<<endl;
} 

template<class T>
SharedPtr<T>::~SharedPtr() {
    // 只在最后一个对象引用ptr时才释放内存
    if(--(*use_count) == 0) {
        delete ptr;
        delete use_count;
        cout<<"Destructor is called!"<<endl;
    } 
}

template<class T>
SharedPtr<T>::SharedPtr(const SharedPtr<T> &orig) {
    ptr = orig.ptr;
    // 这里显示出为什么用int *use_count 
    use_count = orig.use_count;
    ++(*use_count);
    cout<<"Copy constructor is called!"<<endl;
}

// 重载运算为什么返回引用
// https://www.cnblogs.com/codingmengmeng/p/5871254.html 
template<class T>
SharedPtr<T>& SharedPtr<T>::operator=(const SharedPtr<T> &rhs) {
    // 防止自身赋值而导致提早释放内存 
    ++(*rhs.use_count);

    // 将左操作数对象的使用计数减1,若该对象的使用计数减至0,则删除该对象
    if(--(*use_count)==0) {
        delete ptr;
        delete use_count;
    }

    ptr = rhs.ptr;
    use_count = rhs.use_count;

    cout<<"Assignment operator overloaded is called!"<<endl;
    return *this; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值