析构函数似乎被称为'早期'

时间:2010-12-28 22:17:00

标签: c++ memory dynamic destructor

原来这是一个简单的构造函数错误使用问题。 请参阅“修改”部分以获取更新信息。

对不起另一个C ++ dtor问题... 然而,我似乎找不到一个与我一样的东西,因为所有其他人都分配给STL容器(这将删除对象本身),而我的是一个指针数组。

所以我有以下代码片段

#include<iostream>

class Block{
public:
    int x, y, z;
    int type;
    Block(){
        x=1;
        y=2;
        z=3;
        type=-1;
    }
};

template <class T> class Octree{
    T* children[8];
public:
    ~Octree(){
        for( int i=0; i<8; i++){
            std::cout << "del:" << i << std::endl;
            delete children[i];
        }
    }    
    Octree(){
        for( int i=0; i<8; i++ )
            children[i] = new T;
    }
    // place newchild in array at [i]
    void set_child(int i, T* newchild){
        children[i] = newchild;
    }
    // return child at [i]
    T* get_child(int i){
        return children[i];
    }
    // place newchild at [i] and return the old [i]
    T* swap_child(int i, T* newchild){
        T* p = children[i];
        children[i] = newchild;
        return p;
    }
};

int main(){
    Octree< Octree<Block> > here;
    std::cout << "nothing seems to have broken" << std::endl;
}

通过输出我注意到析构函数在我认为应该被调用之前已经被多次调用(因为Octree仍然在范围内),输出的结尾也显示:

del:0
del:0
del:1
del:2
del:3

Process returned -1073741819 (0xC0000005)   execution time : 1.685 s
Press any key to continue.

由于某种原因,析构函数在循环中经过两次相同的点(0)然后死亡。

所有这一切都发生在“没有出现任何错误之前”这一行之前,我预期在任何dtor被召唤之前。

提前致谢:)

修改 我发布的代码删除了一些我认为不必要的东西,但在复制和编译我粘贴的代码后,我不再收到错误。 我删除的是代码的其他整数属性。 这是原始的:

#include<iostream>

class Block{
public:
    int x, y, z;
    int type;
    Block(){
        x=1;
        y=2;
        z=3;
        type=-1;
    }
    Block(int xx, int yy, int zz, int ty){
        x=xx;
        y=yy;
        z=zz;
        type=ty;
    }
    Block(int xx, int yy, int zz){
        x=xx;
        y=yy;
        z=zz;
        type=0;
    }
};

template <class T> class Octree{
    int x, y, z;
    int size;
    T* children[8];
public:
    ~Octree(){
        for( int i=0; i<8; i++){
            std::cout << "del:" << i << std::endl;
            delete children[i];
        }
    }

    Octree(int xx, int yy, int zz, int size){
        x=xx;
        y=yy;
        z=zz;
        size=size;
        for( int i=0; i<8; i++ )
            children[i] = new T;
    }
    Octree(){
        Octree(0, 0, 0, 10);
    }
    // place newchild in array at [i]
    void set_child(int i, T* newchild){
        children[i] = newchild;
    }
    // return child at [i]
    T* get_child(int i){
        return children[i];
    }
    // place newchild at [i] and return the old [i]
    T* swap_child(int i, T* newchild){
        T* p = children[i];
        children[i] = newchild;
        return p;
    }
};

int main(){
    Octree< Octree<Block> > here;
    std::cout << "nothing seems to have broken" << std::endl;
}

另外,至于set_child,get_child和swap_child导致可能的内存泄漏的问题,这将解决,因为包装类将在设置之前使用get或使用swap来获取旧子并在释放之前将其写入磁盘记忆本身。

我很高兴不是我的内存管理失败而是另一个错误。 我还没有制作复制和/或赋值操作符,因为我只是测试块树,我几乎肯定会很快将它们全部设为私有。

此版本吐出-1073741819。

感谢大家的建议,我为劫持我自己的主题而道歉:$

解决 一个构造函数调用另一个构造函数的问题。

感谢所有人的帮助,并在任何时候浪费道歉:)

5 个答案:

答案 0 :(得分:6)

有人定义了构造函数和析构函数,但没有定义复制构造函数。这是被摧毁的副本弄乱了计数。关注rule of three

答案 1 :(得分:3)

它不会经历两次相同的循环。你的顶级八叉树有8个孩子八分,所以你看到嵌套的破坏。我不知道为什么它会死亡。

答案 2 :(得分:3)

问题在于默认构造函数(在编辑之前你没有添加!);它构造了一个临时的Octree实例,我希望你认为它只是调用另一个构造函数:

Octree(){
    Octree(0, 0, 0, 10);
}

正是这个例子,你看到在崩溃前被破坏了。然后,您尝试删除一些从未children编辑(或初始化)的new

将初始化代码从Octree(int, int, int, int )提取到方法中将解决您的问题。例如:

Octree(int xx, int yy, int zz, int size){
    init(xx, yy, zz, size);
}
Octree(){
    init(0, 0, 0, 10);
}

void init(int xx, int yy, int zz, int)
{
    x=xx;
    y=yy;
    z=zz;
    for( int i=0; i<8; i++ )
        children[i] = new T;

}

或者,删除默认构造函数,并为剩余构造函数的每个参数添加默认值:

Octree(int xx = 0, int yy = 0, int zz = 0, int size = 10)
    :x(xx)
    ,y(yy)
    ,z(zz)
    ,size(size)
{
    for( int i=0; i<8; i++ )
        children[i] = new T;
}

但是,真的真的需要处理原始指针吗?如果你这样做,那么你几乎肯定需要在课程有用之前做something about copying

回答your next question, "Nope!" "not until C++11!"

(及其后继者)中:

可以现在委托构造,但语法与您尝试表达的方式略有不同:

Octree()
    :Octree(0, 0, 0, 10)
{
}

答案 3 :(得分:1)

我怀疑你完成了破坏,程序在所有输出写入控制台之前终止。预计事物会经历0两次,因为它是Octree<> 0,然后是Octree<Octree<>> 0。

您需要更改代码以保证析构函数运行,并且在进程退出之前完成所有控制台I / O.

int main(){
 {
  Octree< Octree<Block> > here;
 }
 std::cout << "nothing seems to have broken" << std::endl;
 std::cin.get();
}

当然,这段代码还有很多其他缺陷。但我会从提出的确切问题开始。

答案 4 :(得分:1)

瓦尔格林德说:

==11907== HEAP SUMMARY:
==11907==     in use at exit: 0 bytes in 0 blocks
==11907==   total heap usage: 72 allocs, 72 frees, 1,536 bytes allocated
==11907== 
==11907== All heap blocks were freed -- no leaks are possible