【问题标题】:C+: Destructor for same instance of an object called twiceC +:两次调用的对象的同一实例的析构函数
【发布时间】:2016-09-06 22:35:59
【问题描述】:

所以基本上我在 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;
}

运行时,给我这个输出:

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

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

【问题讨论】:

  • 有什么理由混合使用 c 和 c++ 内存管理?
  • 您需要创建一个复制构造函数来打印以查看发生了什么。这样做,然后检查结果。
  • 你违反了三法则。
  • 去掉m_test_class = Test_Class();这行,没必要,它会导致你的问题。您还应该禁用(或实现)Test_Class 的复制构造函数和复制赋值运算符,这样如果您确实犯了这个错误,编译器就会捕获它。
  • @Kerrek SB 你的意思是五法则吗?

标签: c++ class pointers destructor


【解决方案1】:

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

正确的代码是Game game;

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

编辑

当然,m_Holder 等也是如此。

【讨论】:

  • 对象不能是左值。值类别是表达式的属性,而不是对象。
【解决方案2】:

您可能会受益于对您的班级进行检测以了解正在发生的事情。我经常使用的一种技术是为每个重要事件创建一个带有静态计数器的特定检测类。这是一个示例,它只不过是一个数字类型的包装器(在这种情况下特别是 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

【讨论】:

    【解决方案3】:

    您的代码有很多问题,但无论如何我都会继续使用它。您需要(至少)实现复制构造函数和复制赋值运算符。我会使用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);
    }  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-18
      • 2019-02-24
      • 2015-10-09
      • 2016-11-23
      • 2010-12-29
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      相关资源
      最近更新 更多