zoukankan      html  css  js  c++  java
  • C++ 智能指针(一)

    •   内存安全  

      在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象来进行初始化;delete,接收一个动态对象的指针,销毁该对象,并释放与之关联的内存。

      动态内存的使用很容易出问题,因为确保在正确的时间释放内存是及其困难的。有时我们会忘记释放内存(或程序抛出异常),在这种情况下就会产生内存泄漏;有时在尚有指针引用内存的情况下我们就释放了它,在这种情况下就会产生引用非法内存的指针(段错误)

      下面写个Demo测试程序  

    #include <memory>
    #include <exception>
    #define  FLAG 3    //用于编译不同的程序
    
    class Demo1
    {
    public:
    	Demo1()
    	{
    		std::cout << "Demo1" << std::endl;
    	}
    
    	~Demo1()
    	{
    		std::cout << "~Demo1" << std::endl;
    	}
    };
    
    bool throw_test(bool flag)
    {
    	if (flag)
    	{
    		throw "throw_test";
    	}
    
    	return flag;
    }
    
    int main(int argc, char* argv[])
    {
    	Demo1 *pDemo1 = new Demo1();
    
    	#if (FLAG == 1)
    	throw_test(true);  //1.执行这条语句,会打印~Demo1?
    	#endif
    
    	#if (FLAG == 2)
    	try
    	{
    		throw_test(true);
    	}
    	catch (...)	//2....代表捕获所有异常
    	{
    		delete pDemo1;	//3.执行这条语句,会打印~Demo1?
    		throw;
    	}
    	#endif
    
    	#if (FLAG == 3)
    	delete pDemo1;
    	#endif
    
    	return 0;
    }
    

      上述程序结果如下:

       当宏FLAG为1时,执行throw_test(true),即使程序抛出异常,它没有打印~Demo1;

      当宏FLAG为2时,执行throw_test(true),程序会抛出异常,之后捕获到异常打印~Demo1;

      当宏FLAG为3时,执行delete pDemo1,这是正常操作,程序会调用Demo1的析构函数,打印~Demo1;

    •  智能指针

      C++中的智能指针类型有:auto_ptr,shared_ptr,unique_ptr,weak_ptr(后三者为C++11新增的),它们均为类模板,使用需要包含<memory>头文件

      常规指针带来的风险

    Demo1* pDemo1 = new Demo1();
    Demo1* pDemo2;
    pDemo2 = pDemo1;
    printf("pDemo1:%x pDemo2:%x
    ", pDemo1, pDemo2); 

      上面的pDemo1和pDemo2是常规指针,指向同一个对象(浅拷贝),因此打印的地址也是一样的;请试想一下如果其中一个指针执行了delete操作,那么另一个指针再执行别的操作会怎样?程序会发生段错误。要避免这个问题,可以用下面这些方案:

    1. 定义赋值运算符函数,进行深拷贝,这样的操作会使上面的两个指针不再指向同一个对象,缺点是浪费空间,所以智能指针都未采用此方案
    2. "独占"所指的对象;对于特定的对象,某一时刻只能有一个指针指定一个给定对象,当指针被销毁时,它所指的对象也被销毁,这就是用于auto_ptr和uniqiie_ptr 的策略,但unique_ptr的策略更严格。
    3. 利用引用计数,创建记录型的指针;例如,赋值时,计数将加1,而指针过期时,计数将减1。当减为0时才调用delete。这是shared_ptr采用的策略。

     

      在C++11中,auto_ptr已弃用;编写一段测试程序,Demo1类还是使用上面定义的。

    int main(int argc, char *argv[])
    {
    	std::auto_ptr<Demo1> pDemo1(new Demo1);
    	std::auto_ptr<Demo1> pDemo2;
    	pDemo2 = pDemo1;
    	printf("pDemo1:%p pDemo2:%p
    ", pDemo1, pDemo2);  //运行到这里pDemo1会打印什么?
            return 0;
    }    

      上面的程序运行后,打印pDemo1的地址为NULL。具体可以查看下auto_ptr的赋值运算符的实现是如何的。

      下面这两张截图是VS2015下的auto_ptr的赋值运算符的实现;我们可以看到使用赋值运算符时,会调用reset函数,这是会将_Myptr的内存delete,并将地址置为NULL;如果pDemo1调用成员函数,此时会发送什么?

                       

     

     

        

      

      auto_ptr存在内存崩溃的风险,这个或许就是auto_ptr被C++11弃用的原因吧。

      未完待续...

  • 相关阅读:
    git连接远程分支
    如何找N个数中第i小的数
    DeconvNet
    深度学习中的Internal Convariate Shift (ICS)
    BA算法解决p-中位问题
    蚁群算法
    蝙蝠算法初探
    轨迹压缩之Douglas-Peucker算法之C++实现
    遗传算法---编程小试
    NYOJ 1000
  • 原文地址:https://www.cnblogs.com/coder-zyc/p/9521260.html
Copyright © 2011-2022 走看看