Code Bye

关于智能指针内存泄漏的一点点疑问

其实,本人只是想不懂这程序为啥会内存泄漏,本人单步过了,知道是哪一句导致的,但是想不懂。
// fg.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<string>  
#include<iostream>  
using namespace std;  
template<class T>  
class share  
{  
 public:  
  share():point(0),pcount(NULL){}  
  share(T* p1)  
  {  
	   pcount=new int(0);
       point = p1;  
       if (pcount == NULL)  
       {     
        pcount = new int(1);     
       }         
  }  
  ~share()  
  {  
     if(--(*pcount) == 0)  
     {  
      delete point;  
      delete pcount;  
      pcount = NULL;  
      cout << "begin to delete share" << endl;  
      point = NULL;  
     }  
  }  
  share(share& t2)  
  {  
      point = t2.point;  
	 (*t2.pcount)++;
      pcount =  t2.pcount;  
  }  
  share& operator =(share& t2)  
  {  
      if (--(*pcount) == 0)  
      {  
         delete point;     
      }  
      point = t2.point;  
      t2.(*pcount)++;  
	  cout<<t2.(*pcount)<<endl;
	  cout<<*(t2.pcount)<<endl;
      pcount =  t2.pcount;  
      return *this;  
  }  
  T* operator ->()  
  {  
        return point;  
  }  
private:  
   T* point;  
   int* pcount; //应该用boost::detail::atomic_count
};  
  
class A  
{  
public:  
   A()  
   {  
        n = 0;  
   }  
   int n;  
   char v[4];  
  
};  
  
int main()  
{  
share<A> sp(new(std::nothrow) A());  
sp->n = 10;  
cout << "sp->n is :" << sp->n << endl;  
share<A> sp2 = sp;  
sp2->n = 20;  
cout << "sp->n is :" << sp2->n << endl;  
return 0;  
} 

在初始化时候本人想采用的是

 share():point(0),pcount( new int(0)){}

这种方式初始化,但是pcount每次都初始化失败,为空的。另外在析构函数这里

  ~share()  
  {  
     if(--(*pcount) == 0)  
     {  
      delete point;  
      delete pcount;  
      pcount = NULL;  
      cout << "begin to delete share" << endl;  
      point = NULL;  
     }  
  }

这样就会奔溃,程序已经执行完了,明显是内存泄漏奔溃,但是把单步后定位在

 if(--(*pcount) == 0)

 if(--(*pcount) == 0)

改成

 if((*pcount) == 0)

这样就不会奔溃,纳闷了,假设不–,下面的就没办法执行,就没有释放,程序就不奔溃。

解决方案

10

count 应该和指针一起绑定。
你的count 属于每一个share,而不属于每一个 指针。

30

// 改了一下, 说几点:
// 1. 使用c++11的一些特性, 刚开始学者一开始就学好
// 2. 使用类的构造初始化列表构造对象是一个好习惯
// 3. 复制构造函数的参数是const T&, 不要忘了
// 4. 既然提供了默认构造函数使指针为空, 为什么在析构函数里面以至其他函数都不判断一下?
// 5. c++允许手动调用析构/构造函数, 让operator=写法便利了不少
// 6. 既然知道有std::nothrow 那一步判断能否指针为空不明所以
// 7. 注释上写了最好使用原子操作, 为什么不写进模板参数, 这样本人单线程使用就不用原子操作了
#include <string>
#include <iostream> 
template<class T, class U> class share
{
public:
    share() :point(nullptr), pcount(nullptr) {}
    share(T* p) : point(p), pcount(new U(1)) { }
    ~share() {
        if (!this->pcount) return;
        if (!--(*pcount)) {
            delete point;
            delete pcount;
            //cout << "begin to delete share" << endl;
        }
    }
    share(const share& t2) noexcept : point(t2.point), pcount(t2.pcount) {
        if (this->pcount) (*this->pcount)++;
    }
    share(share&& t2) noexcept : point(t2.point), pcount(t2.pcount) {
        t2.point = nullptr;
        t2.pcount = nullptr;
    }
    share& operator =(share&& t2) noexcept {
        this->share::~share();
        this->share::share(std::move(t2));
        return *this;
    }
    share& operator =(const share& t2) noexcept {
        this->share::~share();
        this->share::share(t2);
        return *this;
    }
    T* operator ->() noexcept { return point; }
private:
    T*      point;
    U*      pcount;
};
class A
{
public:
    A()
    {
        n = 0;
    }
    int n;
    char v[4];
};
int main()
{
    share<A, int> sp(new(std::nothrow) A());
    sp->n = 10;
    std::cout << "sp->n is :" << sp->n << std::endl;
    share<A, int> sp2 = sp;
    sp2->n = 20;
    std::cout << "sp->n is :" << sp2->n << std::endl;
   return 0;
}

10

原地构造要用
new(this) share(t1);
this->share::share(t1); 是不行的。

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明关于智能指针内存泄漏的一点点疑问