检测引用计数对象中的内存泄漏

ana*_*and 6 c++ pointers memory-leaks reference-counting

我正在尝试打印调用addref和release的行.这是代码

在下面的代码中,我在ReferenceCount类上创建了其主要功能,以增加和减少引用计数.Referencemanager类跟踪引用计数,并在对象达到0时删除它.

Test1是测试类.主要是我创建了Test1指针并用CReferenceManager类包装它.现在,在创建CReferenceManager类时,将调用AddRef类,同时调用destroy Release.

如果存在内存泄漏,那么当AddRef和Release调用此时引用计数时,检测是否可以打印出FILE和LINE编号会更容易.

如果有一种方法可以打印调用AddRef和Release的FILE和LINE编号.一种方法是我可以在派生类和prinf FILE和LINE编号中覆盖AddRef和Release

//ReferenceCount.h
#include <string>
#include <Windows.h>

using namespace std;
class CReferenceCount
{
public:
   CReferenceCount();
   virtual ~CReferenceCount();
   virtual void AddRef();
   virtual bool Release();


private:
   LONG m_ref;

};


// RefCount.cpp 
//

#include "stdafx.h"
#include "ReferenceCount.h"


CReferenceCount::CReferenceCount():m_ref(0)
{
   AddRef();

}

CReferenceCount::~CReferenceCount()
{
}

void CReferenceCount::AddRef()
{
    InterlockedIncrement(&m_ref);
}

bool CReferenceCount::Release()
{
   if (InterlockedDecrement(&m_ref) == 0)
   {
      delete this;
      return true;
   }

   return false;
}



//ReferenceManager.h
#include <string>
#include <Windows.h>

using namespace std;
class CReferenceCount
{
public:
   CReferenceCount();
   virtual ~CReferenceCount();
   virtual void AddRef();
   virtual bool Release();


private:
   LONG m_ref;

};

//test.cpp
#include "stdafx.h"
#include "ReferenceCount.h"
#include "RefManager.h"
#include <iostream>
using namespace std;

class Test1: public CReferenceCount
{
public:
    Test1(){}
    ~Test1(){}

private :
    int m_i;
};

void main()
{
    Test1 *pTest= new Test1();
    CReferenceManager<Test1> testRef(pTest);

}
Run Code Online (Sandbox Code Playgroud)

我发布的Similare问题 发现了谁通过智能指针创建对象 设计模式来检测内存泄漏,以便参考计数智能指针

但没有答案给出正确的解释来解决这个问题,

Rol*_*lie 6

唯一的方法是定义用于调用AddRef和Release的宏,因为函数无法从内部知道它们被调用的位置.所以你可以使用类似的东西.

#define RELEASE(obj) cout << __LINE__ << ":" << __FILE__ << endl; (obj).Release();
Run Code Online (Sandbox Code Playgroud)

此外,不同的编译器具有不同的预定义宏; 如果可移植性是一个问题,那么在编写如上所述的代码时应该考虑一下.MSDN参考(2003)

鉴于您的评论如下,我可能会提供另一个有点hackish的解决方案.您可能无法查看引用的发布位置,但您可以获得有关其创建位置以及未正确发布的更多信息.

template <typename T>
struct CReferenceManager
{
    CReferenceManager(const T & _obj, const string & _file, int _line) : mObj(_obj), mFile(_file), mLine(_line)
    {
        cout << "Constructing from " << _file << ":" << _line << endl;
        CReferenceManager::sObjects[make_pair(mFile, mLine)]++;
        mObj.addRef();
    }

    ~CReferenceManager()
    {
        cout << "Destructing object created at " << mFile << ":" << mLine << endl;
        CReferenceManager::sObjects[make_pair(mFile, mLine)]--;
        mObj.Release();
    }

    static map<pair<string, int>, int> sObjects;
    string mFile;
    int mLine;
    T obj;
}

int main()
{
...
    // Cycle through sObjects before return, note any unreleased entries
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

注意这只是伪代码; 我怀疑它编译或开箱即用!


Mig*_*uel 5

你永远不应该在自己的代码中明确地分配或释放引用,因此存储源文件和引用递增或递减的行根本不会对你有帮助,因为那些(应该!)总是在引用计数管理中码.

您没有将源代码包含在CReferenceManager类中,但根据您的描述,它是引用计数对象的包装器.它是否正确?正确实现此CReferenceManager对象应确保:

  • 采用裸指针的构造函数存储指针并且不会更改引用计数(因为您的CReferenceCount类使用一个引用创建对象)
  • 引用总是在析构函数中递减
  • 引用在复制构造函数中递增
  • 右侧对象的引用递增,并且左侧对象的引用在赋值运算符中递减
  • 不应暴露显式增量/减量参考方法
  • operator - >()方法应该返回指向对象的指针
  • 应该没有直接的方法将引用计数对象从拥有它的CReferenceManager实例中分离出来.唯一的方法是通过分配新的引用计数对象.

此外,您希望将CReferenceCount类中的AddRef()Release()方法设为私有,并且只能通过类友谊访问CReferenceManager类.

如果您在CReferenceManager类中遵循上述规则,那么您可以通过确保每个人通过堆栈上分配的CReferenceManager包装器访问对象来避免泄漏或其他内存问题.换一种说法:

要创建新引用的计数对象,请将新创建的对象(带有一个引用)传递给堆栈分配的CReferenceManager对象.例:

CReferenceManager<Test1> testRef(new Test1());
Run Code Online (Sandbox Code Playgroud)

要将对象作为参数传递给另一个函数或方法,请始终按值传递CReferenceManager对象(不是通过引用,而不是通过指针).如果这样做,复制构造函数和析构函数将负责为您维护引用计数.例:

void someFunction(CReferenceManager<Test1> testObj)
{
    // use testObj as if it was a naked pointer
    // reference mananagement is automatically handled
    printf("some value: %d\n", testObj->someValue());
}

int main()
{
    CReferenceManager<Test1> testRef(new Test1());
    someFunction(testRef);
}
Run Code Online (Sandbox Code Playgroud)

如果您需要将引用计数对象粘贴在容器中,则按值插入CReferenceManager包装器(不是其指针,而不是对象的裸指针).例:

std::vector< CReferenceManager<Test1> > myVector;
CReferenceManager<Test1> testRef(new Test1());
myVector.push_back(testRef);
myVector[0]->some_method(); // invoke the object as if it was a pointer!
Run Code Online (Sandbox Code Playgroud)

我相信如果你严格遵守上述规则,你会发现的唯一问题是你的引用计数实现中的错误.

遵循这些规则的示例实现在此页面中,尽管该解决方案缺乏对多线程保护的任何支持.

我希望这有帮助!