• SmartPointer_智能指针


    动态内存

    C++中程序用来存储动态分配(dynamically allocate)的对象——即那些在程序运行时分配的对象。

    动态内存的生存期由程序控制,也就是当动态对象不再使用时,我们必须显示的销毁它们。

    But众所周知(王小波句式),正确的管理动态内存是非常棘手的。如果忘了释放内存,就会导致内存泄漏;如果在还有指针引用内存时就去释放那块内存,那么那个指针就会变为一个引用非法内存的指针。thorny problem!

    智能指针原理

    So, 为了更容易更安全的使用动态内存,新的标准库提供了智能指针(smart pointer)类型来管理动态对象。

    智能指针的行为类似常规指针,区别是它负责自动释放所指向的对象。

    那么smart pointer是如何做到自动释放内存的呢?

    其实,智能指针是一个类类型,假如给它起个类名叫SmartPtr吧。在这个SmartPtr类中,有一个private成员变量,这个变量是另外一种类类型的指针(就是说它是一个指针,指向一个类),然后通过这个指针来动态创建类的对象。

    比如,这里创建了SmartPtr类和Animal类,SmartPtr中的成员变量ptr_为Animal类的一个指针。

    代码如下:

    #ifndef SMARTPTR
    #define SMARTPTR 
    
    #include <iostream>
    
    //禁用赋值与复制
    #define DISALLOW_COPY_AND_ASSIGN(TypeName) 
        TypeName(const TypeName&); 
        void operator=(const TypeName&)
    
    class Animal
    {
        public:
    
            Animal()
            {
                std::cout << "construct......." << std::endl;
            }
    
            ~Animal()
            {
                std::cout << "destruct ... " << std::endl;
            }
            void run()
            {
                std::cout << "running......." << std::endl;
            }
    };
    
    
    class SmartPtr
    {
        public:
            //SmartPtr针对的是heap上的对象
            SmartPtr(Animal *ptr);
            ~SmartPtr();
    
            Animal &operator*();
            const Animal &operator*() const;
    
            Animal *operator->(); //重载SmartPtr这个类的->
            const Animal *operator->() const;
        private:
            DISALLOW_COPY_AND_ASSIGN(SmartPtr);
            Animal *ptr_; 
    };
    
    #endif  /*SMARTPTR*/
    
    SmartPtr::SmartPtr(Animal *ptr)
        :ptr_(ptr)
    {
    }
    
    SmartPtr::~SmartPtr()
    {
        delete ptr_; //SmartPtr析构时释放指向Animal类的指针,从而释放内存
    }
    
    Animal &SmartPtr::operator*()
    {
        return *ptr_;
    }
    
    //const 版本 const Animal &SmartPtr::operator*() const { return *ptr_; } Animal *SmartPtr::operator->() { return ptr_; } //const版本 const Animal *SmartPtr::operator->() const { return ptr_; }

     然后我们编写一个异常处理函数来测试一下:

    #include <stdexcept>
    #include "SmartPtr.hpp"
    using namespace std;
    
    int main(int argc, const char *argv[])
    {
        try{
            //这里的ptr离开try时一定会被销毁
            //从而导致Animal对象一定会被析构
            SmartPtr ptr(new Animal);
            throw runtime_error("error");
    
        }catch(runtime_error &e)
        {
            cout << e.what() << endl;
    		/*
    		construct...
    		destruct...
    		error
    		*/
        }
        return 0;
    }
    

    这里补充一点:在异常处理函数中,如果在栈展开过程中退出了某个块(执行到throw语句),编译器将会负责确保在这个块中的对象能被正确的销毁。如果某个局部对象的类型是类类型,则该对象的析构函数将会被自动调用。

    所以,上面程序中当执行到throw语句时,直接跳到catch中继续运行。那么原来try中的东东会确保被销毁,也就是编译器自动会去调用ptr这个对象的析构函数,从而执行了delete ptr_, 所以存储Animal对象的内存就被自动释放了。

    一句话,智能指针利用了栈对象的生存期,将资源的获取放在构造函数里面,资源的释放放在析构函数里面,从而保证了资源一定会被正确释放。

    最后,这也就是C++中的RAII(Resource Acquirement Is Initialization)

    RAII要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。

  • 相关阅读:
    大前端完整学习路线(详解)
    浅谈攻击Web应用常见的技术手段
    浅谈XSS跨站脚本攻击
    利用SQL注入漏洞登录后台
    1、MyBatis框架底层初涉
    1、用静态工厂方法代替构造器
    日志管理-log4j与slf4j的使用
    Java的值类型和引用类型
    自动任务调度
    2、Hibernate持久化编写
  • 原文地址:https://www.cnblogs.com/beatrice7/p/4123737.html
Copyright © 2020-2023  润新知