atomic<int> cntMyObject;
我在析构函数中减少对象实例计数,在构造函数中增加对象实例计数,在复制构造函数中也这样做(我希望我覆盖了所有内容 :))。但这对每个类来说都是硬编码的,并且在“Release”模式下禁用它并不简单。 所以,有没有一种简单而优雅的方法可以轻松禁用对象实例计数?
atomic<int> cntMyObject;
我在析构函数中减少对象实例计数,在构造函数中增加对象实例计数,在复制构造函数中也这样做(我希望我覆盖了所有内容 :))。但这对每个类来说都是硬编码的,并且在“Release”模式下禁用它并不简单。 所以,有没有一种简单而优雅的方法可以轻松禁用对象实例计数?
创建一个“计数对象”类,它在其构造函数和析构函数中进行适当的引用计数,然后从中派生您想要跟踪的对象。然后可以使用奇妙的重复模板模式来获取任何您希望跟踪的对象类型的不同计数。
// 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>
{};
total_
增加吗? - Flow你可以采用这种方法。
#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()
方法将返回创建的对象数量。
new
和delete
运算符,然后在其中实现内存诊断。new
在失败的情况下不应该只是抛出 std::bad_alloc
吗? - Alok Save如果不了解您的代码和要求,我认为有两个合理的选择:
a) 使用 boost::shared_ptr
。它内置了您建议的原子引用计数并处理内存管理(因此您实际上永远不需要关心计数)。 它的引用计数可以通过 use_count()
成员获得。
b) 如果像a)一样的含义,例如处理指针和在各处使用 shared_ptrs
或可能的性能开销对您不可接受,我建议简单地使用可用的内存泄漏检测工具(例如 Valgrind,见上文),这将在程序退出时报告您的未释放对象。而且没有必要使用侵入式辅助类来跟踪对象计数(无论如何仅限于调试),它们只会混乱您的代码,我个人认为。
#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>
一些答案中讨论了将计数器添加到单个类中。但是,这需要选择要计数的类并以某种方式修改它们。以下假设您正在添加此类计数器以查找保留比预期更多某些类的对象的错误。
简要回顾已经提到的一些事情:对于真正的内存泄漏,当然有valgrind:memcheck和泄漏消毒剂。但是,对于其他没有真正泄漏的情况,它们无法帮助(未清除的向量、从未访问键的映射条目、shared_ptr的循环等)。
但是,由于这没有被提到:在valgrind工具套件中还有massif,它可以为您提供有关所有分配的内存块及其分配位置的信息。但是,假设valgrind:massif对您也不可行,并且您确实想要实例计数。
如果你愿意尝试一些hackish的解决方案,而且上述选项都不起作用,为了偶尔进行bug调试,你可以考虑以下方法:现在,堆上的许多对象实际上由智能指针持有。这可以是标准库中的智能指针类,也可以是您使用的相应辅助库的智能指针类。然后,技巧就在于(以shared_ptr为例):通过修改shared_ptr实现,即向shared_ptr类添加实例计数器,可以一次获取许多类的实例计数器。然后,对于某个类Foo,属于shared_ptr<Foo>的计数器将为您提供类Foo的实例数量的指示。
当然,它并不像直接将计数器添加到各自的类中那样精确(仅由裸指针引用的实例不计入),但可能对您的情况足够准确。当然,这与永久更改智能指针类无关-只是在调试bug时。至少,智能指针实现不太复杂,因此对它们进行修补很简单。
这种方法比这里的其他解决方案简单得多。
为计数制作一个变量,并使其静态。在构造函数中将该变量增加1,在析构函数中将其减少1。
确保初始化变量(不能在标题中初始化,因为它是静态的)。
.h
// Pseudo code warning
class MyObject
{
MyObject();
~MyObject();
static int totalObjects;
}
.cpp
int MyObject::totalObjects = 0;
MyObject::MyObject()
{
++totalObjects;
}
MyObject::~MyObject()
{
--totalObjects;
}