C +:两次调用对象的同一实例的析构函数

时间:2016-05-11 13:25:44

标签: c++ class pointers destructor

所以基本上我在VS2013中有一些看起来像这个

的c ++代码
#include "stdafx.h"
#include <malloc.h>
#include <stdio.h>

class Test_Class {
public:
    Test_Class() {
        printf("In Test_Class()\n");
        allocated_array = (int*)malloc(sizeof(int) * 64);
        printf("Allocated %p\n", allocated_array);
    }

    ~Test_Class() {
        printf("In ~Test_Class()\n");
        printf("Freeing %p\n", allocated_array);
        free(allocated_array);
        printf("Freed %p\n", allocated_array);
    }
private:
    int* allocated_array;
};

class Holder {
public:
    Holder() {
        printf("In Holder()\n");
        m_test_class = Test_Class();
    }

    ~Holder() {
        printf("In ~Holder()\n");
    }
private:
    Test_Class m_test_class;
};

class Game {
public:
    Game() {
        printf("In Game()\n");
        m_holder = Holder();
    }

    ~Game() {
        printf("In ~Game()");
    }
private:
    Holder m_holder;
};

int main()
{
    printf("In main()\n");
    Game game = Game();
    return 0;
}

当跑步时,给我这个输出:

http://i.imgur.com/g8vCdIo.png

我想知道的是,为什么同一个Test_Class对象的析构函数在崩溃之前被调用两次(由于试图释放两次相同的指针)。我使用了调试器,以确保它不仅仅是一个新的类实例,它被赋予了与另一个对象相同的指针,而且确实它是完全相同的对象。

据我所知,由于Test_Class对象是Holder的成员,它会创建一个Test_Class对象,然后创建另一个对象并销毁旧对象(它似乎在做),但是这种调用析构函数的奇怪行为当我在Game类中创建Holder类型的成员时,似乎也会出现同样的情况。显然有些东西我不见了。

3 个答案:

答案 0 :(得分:7)

原因是,您的编译器无法消除副本分配Game game = Game();

正确的代码是Game game;

您的代码所做的是将对象构造为rvalue,将其分配给作为左值的新对象game。所以在这一行中Game game = Game();构造了两个对象,其中一个在分配后立即被破坏。

修改

同样适用于m_Holder等等 - 当然。

答案 1 :(得分:1)

您可以通过检查课程来了解发生了什么。我经常使用的一种技术是为每个重要事件创建一个带有静态计数器的特定检测类。这里有一个例子,它只是一个数字类型的包装器(在这种情况下特别是double),但它说明了这个想法:

class Goofy
{
private:
    double num;
public:
    Goofy(double n = 0) : num(n) { ++constructions; }
    Goofy(const Goofy &g2) : num(g2.num) { ++copyconstructions; }
    Goofy(const Goofy &&g2) : num(g2.num) { ++moves; }
    ~Goofy() { ++destructions; }
    Goofy &operator=(const Goofy &g2) { num = g2.num; return *this; }
    Goofy &operator-=(const Goofy &g2) { num -= g2.num; return *this; }
    Goofy &operator+=(const Goofy &g2) { num += g2.num; return *this; }
    // none of the code below is needed by the new version of the function
    Goofy &operator*=(const Goofy &g2) { num *= g2.num; return *this; }
    friend std::ostream &operator<<(std::ostream &out, const Goofy &g2) {
        return out << g2.num;
    }
    static void report(int line) {
        std::cout << "At line " << line
              << "\nconstructions = " << Goofy::constructions
              << "\n       copies = " << Goofy::copyconstructions
              << "\n        moves = " << Goofy::moves 
              << "\n destructions = " << Goofy::destructions 
              << "\n     existing = " << Goofy::constructions + 
                    Goofy::copyconstructions + Goofy::moves - 
                    Goofy::destructions
              << '\n';
    }
    static long constructions;
    static long copyconstructions;
    static long moves;
    static long destructions;
};

long Goofy::constructions = 0;
long Goofy::copyconstructions = 0;
long Goofy::moves = 0;
long Goofy::destructions = 0;

以下是如何使用它的示例:https://codereview.stackexchange.com/questions/56532/kahan-summation/56592#56592

答案 2 :(得分:0)

您的代码存在很多问题,但无论如何我都会使用它。您需要(至少)实现复制构造函数和复制赋值运算符。我会使用newdeleteswap,因为这是C ++而不是C.这样的事情:

Test_Class() {
    allocated_array = new int[64];
}

~Test_Class() {
    delete[] allocated_array;
}

Test_Class(const Test_Class& rhs)
{
    allocated_array = new int[64];
    std::copy(&rhs.allocated_array[0], &rhs.allocated_array[0] + 64, &allocated_array[0]);
}

Test_Class& operator=(const Test_Class rhs)
{
    if (this != &rhs)
    {
        Test_Class(rhs).swap(*this);
    }

    return *this;
}

void swap(Test_Class & s) throw()
{
    std::swap(this->allocated_array, s.allocated_array);
}