C ++析构函数未被调用/对象未被删除 - 潜在的内存泄漏

时间:2014-07-30 21:03:26

标签: c++ memory memory-leaks constructor destructor

我的第一个问题是:我在弄清楚为什么构造类比其他类更大时遇到了很多麻烦。下面是一个简短的应用程序,使用模板计数器来跟踪为每个类调用构造函数/析构函数/复制构造函数的次数。总共有三个类:示例,Deep,Child。每个人都有一个复制构造函数......呃。

另外,我的第二个问题是,为Child类定义复制构造函数的正确方法是什么?

在printStatus()中,它显示:

COUNTERS::NEW_COUNTER = 60
COUNTERS::DELETE_COUNTER = 50
COUNTERS::CONSTRUCTOR_COUNTER = 90
COUNTERS::DESTRUCTOR_COUNTER = 80
Example count = 10
Deep count = 0
Child count = 0

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class COUNTERS
{
    public:
        static int NEW_COUNTER;
        static int DELETE_COUNTER;
        static int CONSTRUCTOR_COUNTER;
        static int DESTRUCTOR_COUNTER;  
};

int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;

/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
    static unsigned cs_count_;
public:
    Countable() { ++cs_count_; }
    Countable( Countable const& ) { ++cs_count_; }
    virtual ~Countable() { --cs_count_;}
    static unsigned count() { return cs_count_; }
};

template <typename T>
unsigned Countable<T>::cs_count_ = 0;

class Example : public Countable<Example>
{
    public:
        string a;
        int b;

        Example()        {
            COUNTERS::CONSTRUCTOR_COUNTER++;

            a = "exampleString";
            b = 5;
        }

        virtual ~Example()        {
            COUNTERS::DESTRUCTOR_COUNTER++;
        }

        // copy constructor
        Example(const Example& e)        {
            COUNTERS::CONSTRUCTOR_COUNTER++;

            this->a = e.a;
            this->b = e.b;
        }
};

class Deep  : public Countable<Deep>
{
    public:
        int a;
        string b; 
        Example* e;

        Deep()      
        {
            COUNTERS::CONSTRUCTOR_COUNTER++;

            a = 3;
            b = "deepString";
            e = new Example();
            COUNTERS::NEW_COUNTER++;
        }

        virtual ~Deep()     {
            if(e != NULL)           {
                delete e;
                COUNTERS::DELETE_COUNTER++;
            }
            COUNTERS::DESTRUCTOR_COUNTER++;
        }

        // copy constructor
        Deep(const Deep& x)
        {
            COUNTERS::CONSTRUCTOR_COUNTER++;

            this->a = x.a;
            this->b = x.b;

            this->e = new Example(); 
            COUNTERS::NEW_COUNTER++;

            this->e->a = x.e->a;
            this->e->b = x.e->b;
        };
};

class Child  : public Countable<Child>
{
    public:
        Deep d;
        string name;
        int age;
        Example* e;

        vector<Example> list;
        vector<Deep> deep_list;

        void init()
        {
            Deep* var = new Deep(); COUNTERS::NEW_COUNTER++;
            deep_list.push_back(*var);
            delete var; COUNTERS::DELETE_COUNTER++;
        }

        Child() {
            COUNTERS::CONSTRUCTOR_COUNTER++;

            name = "a";
            age = 10;
            d.a = 1;
            d.b = "deep";
            d.e = NULL;

            e = new Example();
            COUNTERS::NEW_COUNTER++;

            list.push_back(*e);

            init();
        }

        virtual ~Child()        {
            COUNTERS::DESTRUCTOR_COUNTER++;
            if(e != NULL)           {
                delete e;
                COUNTERS::DELETE_COUNTER++;
            }
        }

        // copy constructor
        Child(const Child& c)
        {

        }
};

void myChildFunction(){
    Child* c = new Child();
    COUNTERS::NEW_COUNTER++;

    delete c;
    COUNTERS::DELETE_COUNTER++;
}

void printStatus(){
    cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
    cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
    cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
    cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;

    cout << "Example count = " << Example::count() << endl;
    cout << "Deep count = " << Deep::count() << endl;
    cout << "Child count = " << Child::count() << endl;
}

int main() 
{
    for(unsigned int i=0 ; i < 10; i++) 
        myChildFunction();  

    printStatus();
    return 0;
}

2 个答案:

答案 0 :(得分:1)

由于以下行,您错过了删除某些Example个对象:

     d.e = NULL;
Child::Child()中的

您正在e的构造函数中为Deep分配内存。执行上述行后,该内存泄露。

您可以通过以下方式解决该问题:

  1. 删除该行(或将其注释掉),
  2. 在将d.e设为NULL或
  3. 之前删除它
  4. 做一些防止内存泄漏的事情。
  5. 更新,以回复评论

    Child的复制构造函数:

      Child(const Child& c) : d(c.d),
                              name(c.name),
                              age(c.age),
                              e(new Example(*c.e)),
                              list(c.list),
                              deep_list(c.deep_list)
      {
         COUNTERS::DESTRUCTOR_COUNTER++; // This is for Child
         COUNTERS::NEW_COUNTER++;        // This is for new Example   
      }
    

答案 1 :(得分:1)

我删除了使代码混乱的所有信息。 当使用模板,构造函数和复制构造函数时需要以下内容:示例&lt; eltType&gt;(void); 在类定义中。从Countables继承的所有对象都称为派生类。它们也可以将派生类称为子类,并将派生它的类称为父类。我添加了COPY_CONSTRUCTOR_COUNT以向控制台/命令提示符下显示的数据添加说明。通常在尝试执行大型或小型任务时,通过逐步执行任务并为每项任务提供方法,可以节省您的时间和头痛。我从等式中删除了new_count和delete_count,因为我觉得不需要它。

你会注意到我添加了:Countable(*((Countable&lt; eltType&gt; *)&amp; e)) 在设计涉及继承的程序时,这是一个要求,它引入了 多态性主题:D

这段代码的作用是它获得一个Countable的指针,它将指向对象e的地址,然后允许访问该类的所有超类,但不包括e的类。

注意:由于e是Countable的派生类,因此这是有效语句。

对于第二个问题,所有数据成员都是公共的,您可以使用迭代器来复制存储在向量中的数据。

作为一个程序员对另一个程序员的关注,我希望您的代码在实践中有详细记录,并且您的类中声明的所有方法都在.cpp文件中定义。

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class COUNTERS
{
public:
static int NEW_COUNTER;
static int DELETE_COUNTER;
static int CONSTRUCTOR_COUNTER;
static int DESTRUCTOR_COUNTER;
static int COPY_CONSTRUCTOR_COUNTER;
};

int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;
int COUNTERS::COPY_CONSTRUCTOR_COUNTER = 0;

/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
public:
Countable<T>() 
{ 
    incrementObjectCount(); 
};

Countable<T>(Countable const&) 
{ 
    incrementObjectCount(); 
};

virtual ~Countable() 
{
    decrementObjectCount(); 
};

static unsigned count() 
{ 
    return cs_count_; 
};

protected:
static unsigned cs_count_;

////////////////////////////////////ADDED////////////////////////////////////
protected:
void incrementObjectCount(void){ ++cs_count_; };
void decrementObjectCount(void){ --cs_count_; };
void incrementDeconstructorCounter(void){ ++COUNTERS::DESTRUCTOR_COUNTER; };
/////////////////////////////////////ADDED////////////////////////////////////
};

template <typename T>
unsigned Countable<T>::cs_count_ = 0;

class Example : public Countable<Example>
{
public:


Example() : Countable<Example>() 
{
    COUNTERS::CONSTRUCTOR_COUNTER++;
}

virtual ~Example()        
{
    incrementDeconstructorCounter();
}

// copy constructor
Example(const Example& e) : Countable<Example>(*((Countable<Example>*)&e))
{
    // COUNTERS::CONSTRUCTOR_COUNTER++; This is copy constructor, you addmitted this from     "Child"     class CCstr
    ++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};

class Deep : public Countable<Deep>
{
public:

Deep() : Countable<Deep>()
{
    COUNTERS::CONSTRUCTOR_COUNTER++;
}

virtual ~Deep()     
{
    COUNTERS::DESTRUCTOR_COUNTER++;
}

// copy constructor
Deep(const Deep& x) : Countable<Deep>(*((Countable<Deep>*)&x))
{
    //COUNTERS::CONSTRUCTOR_COUNTER++;
    ++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
};
};


class Child : public Countable<Child>
{
public:

vector<Example> list;
vector<Deep> deep_list;

void init()
{
    deep_list.push_back(Deep()); 
    list.push_back(Example());
}

Child() : Countable<Child>() 
{
    COUNTERS::CONSTRUCTOR_COUNTER++;
    init();
}

virtual ~Child()        
{
    COUNTERS::DESTRUCTOR_COUNTER++;
}

// copy constructor
Child(const Child& c) : Countable<Child>(*((Countable<Child>*)&c))
{
    ++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};

void myChildFunction(){
Child* c = new Child();
//COUNTERS::NEW_COUNTER++;not needed

delete c;
//COUNTERS::DELETE_COUNTER++; not need
}

void printStatus(){



cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;
cout << "COUNTERS::COPY_CONSTRUCTOR_COUNTER = " << COUNTERS::COPY_CONSTRUCTOR_COUNTER << endl;

cout << "Example count = " << Example::count() << endl;
cout << "Deep count = " << Deep::count() << endl;
cout << "Child count = " << Child::count() << endl;
}

int main()
{
for (unsigned int i = 0; i < 10; i++)
    myChildFunction();

printStatus();
system("pause");
return 0;
}