c++ 计算对象示例数的最简单方法

8xiog9wr  于 2023-01-22  发布在  其他
关注(0)|答案(9)|浏览(174)

我想知道在某个执行点分配的某些对象的示例的确切数量。主要是为了寻找可能的内存泄漏(我主要使用RAII,几乎没有新的,但我仍然可以忘记。在添加新元素或类似的东西之前清除()对vector)。

atomic<int> cntMyObject;

我--在析构函数中,++在构造函数中增加,cpy构造函数(我希望我涵盖了所有内容:))。但这是每个类的硬编码。而且在“释放”模式中禁用它并不简单。所以有什么简单优雅的方法可以很容易地禁用来计数对象示例吗?

qgelzfjb

qgelzfjb1#

有一个“计数对象”类,在它的构造函数和析构函数中进行正确的引用计数,然后从它派生出你想要跟踪的对象,然后你可以使用奇怪的循环模板模式来获得你想要跟踪的任何对象类型的不同计数。

// warning: pseudo code

template <class Obj>
class CountedObj
{
public:
   CountedObj() {++total_;}
   CountedObj(const CountedObj& obj) {++total_;}
   ~CountedObj() {--total_;}

   static size_t OustandingObjects() {return total_;}

private:
   static size_t total_;
};

class MyClass : private CountedObj<MyClass>
{};
envsm3lx

envsm3lx2#

您可以应用此方法

#ifdef DEBUG

class ObjectCount {
    static int count;
  protected:
    ObjectCount() {
        count++;
    }
  public:
    void static showCount() {
        cout << count;
    }
};

int ObjectCount::count = 0;

class Employee : public ObjectCount {
#else
class Employee {
#endif
  public:
    Employee(){}
    Employee(const Employee & emp) {

    }
};

DEBUG模式下,调用ObjectCount::showCount()方法将返回创建的对象的计数。

t5fffqht

t5fffqht3#

最好使用内存分析和泄漏检测工具,比如Valgrind或者RationalPurify。
如果你不能并且想要实现你自己的机制,
应该为类重载newdelete运算符,然后在它们中实现内存诊断。
看看这个C++常见问题解答,了解如何做到这一点以及应该采取哪些预防措施。

z8dt9xmd

z8dt9xmd4#

这是一个类似的例子:http://www.almostinfinite.com/memtrack.html(只需复制页面末尾的代码并将其放入Memorytrack. h,然后运行TrackListMemoryUsage()或其他函数之一来查看诊断信息)
它覆盖了new操作符,并做了一些《双城之战》的宏操作,使它在每个分配中“标记”一个对象有多少示例,以及它们使用了多少内存。尽管它并不完美,但它们使用的宏在某些情况下会崩溃。如果你决定尝试这个操作,请确保将它包含在任何标准的头部之后。

d4so4syb

d4so4syb5#

在不了解您的代码和需求的情况下,我认为有两个合理的选择:
a)使用boost::shared_ptr。它内置了您建议的原子引用计数,并负责您的内存管理(因此您实际上永远不会关心计数)。它的引用计数可通过use_count()成员获得。
B)如果您无法接受a)的影响,比如处理指针和到处都有shared_ptrs,或者可能的性能开销,我建议您使用可用的工具进行内存泄漏检测(例如Valgrind,见上文),它会在程序退出时报告您的松散对象。并且不需要使用侵入式的帮助类来(无论如何调试只)跟踪对象计数,这只是搞乱你的代码,恕我直言。

busg9geu

busg9geu6#

我们曾经有一个内部计数器的基类的解决方案,并从它派生,但我们把它全部改为boost::shared_ptr,它保留了一个引用计数器,并为你清理内存。boost智能指针家族相当有用:boost smart pointers

slwdgvem

slwdgvem7#

我的方法是将泄漏计数输出到DebugOutput(通过在我们的代码库中实现的DebugPrint函数,用您自己的调用替换那个调用...)

#include <typeinfo> 
#include <string.h>
class CountedObjImpl
{
public:
        CountedObjImpl(const char* className) : mClassName(className) {}
        ~CountedObjImpl()
        {
                DebugPrint(_T("**##** Leakage count for %hs: %Iu\n"), mClassName.c_str(), mInstanceCount);
        }
        size_t& GetCounter() 
        {
                return mInstanceCount;
        }

private:
        size_t mInstanceCount = 0;
        std::string mClassName;
};

template <class Obj>
class CountedObj
{
public:
        CountedObj() { GetCounter()++; }
        CountedObj(const CountedObj& obj) { GetCounter()++; }
        ~CountedObj() { GetCounter()--; }

        static size_t OustandingObjects() { return GetCounter(); }

private:
        size_t& GetCounter()
        {
                static CountedObjImpl mCountedObjImpl(typeid(Obj).name());
                return mCountedObjImpl.GetCounter();
        }
};

示例用法:

class PostLoadInfoPostLoadCB : public PostLoadCallback, private CountedObj<PostLoadInfoPostLoadCB>
2w3rbyxf

2w3rbyxf8#

在一些答案中讨论了向单个类添加计数器。但是,这需要选择要计数的类,并以某种方式修改它们。下面的假设是,您添加此类计数器是为了查找某些类中保持活动的对象比预期的多的错误。
简要回顾一下已经提到的一些事情:对于真实的的内存泄漏,当然有valgrind:memcheck和泄漏清理程序,但是,对于其他没有真正泄漏的场景,它们没有帮助(未清除的向量,从未访问过键的Map条目,shared_ptrs的循环,...)。
但是,由于这是没有提到:在valgrind工具套件中也有massif,它可以提供所有已分配内存的信息以及它们被分配到哪里,但是,让我们假设valgrind:massif也不是一个选项,并且您确实需要示例计数。
为了偶尔寻找bug--如果你愿意接受一些黑客式的解决方案,而上面的方法都不起作用--你可以考虑以下方法:现在,堆上的很多对象都被智能指针有效地控制着,这可以是标准库中的智能指针类,也可以是你所使用的各个助手库中的智能指针类,技巧如下(以shared_ptr为例):你可以通过修补shared_ptr的实现,也就是通过给shared_ptr类添加示例计数器,来一次获得很多类的示例计数器,然后,对于某些类Foo,属于shared_ptr的计数器会给予你类Foo的示例数的指示。
当然,它不如直接将计数器添加到相应的类中那样精确(只对原始指针引用的示例不计数),但对于您的情况来说,它可能已经足够精确了。当然,这并不是永久地更改智能指针类--只是在查找bug期间。至少,智能指针的实现并不太复杂,因此修补它们很简单。

a7qyws3x

a7qyws3x9#

这种方法比这里的其他解决方案要简单得多。
为计数创建一个变量并使其静态化。在构造函数中将该变量增加+1,在析构函数中将其减少-1。
确保初始化了变量(因为它是静态的,所以不能在头内初始化)。

.h

// Pseudo code warning
class MyObject
{
   MyObject();
   ~MyObject();
   static int totalObjects;
}

.菲律宾共产党

int MyObject::totalObjects = 0;

MyObject::MyObject()
{
   ++totalObjects;
}

MyObject::~MyObject()
{
   --totalObjects;
}

对于您创建的每个新示例,都会调用构造函数,并且totalObjects会自动增加1。

相关问题