C++ 析构函数调用了错误的对象?

Samueljh1

我是 C++ 的新手,我写了一个小程序来了解赋值是如何处理对象的。我被提示从本页 ( http://www.cplusplus.com/doc/tutorial/classes2/ )的 cpp 文档中执行此操作在此页面上,它指出:

[复制赋值运算符的]隐式版本执行适用于许多类的浅拷贝,但不适用于具有指向它们处理其存储的对象的指针的类。在这种情况下,不仅类会招致两次删除所指向对象的风险,而且由于在赋值之前不删除对象所指向的对象,赋值会造成内存泄漏

我用粗体格式化的最后一部分是我决定测试的原因。我认为这个问题可以通过在析构函数中处理指向对象的删除来解决(这是标准的?),而不必重载复制赋值运算符。如果没有调用析构函数,那不是真的很不方便吗?假设我有多个引用的对象,我必须将所有删除都放在析构函数(对于大多数重新分配的情况)和赋值重载中。

在这次测试中,我遇到了一个完全不同的问题。我最初的想法是创建一个简单的类,它存储一个 int(作为测试目的的标识符)并重载构造函数和析构函数以查看何时以及是否调用析构函数。

这是我的代码:

class Test{
public:
    int id;
    explicit Test(int id) : id(id) {
        cout << "Created " << id << endl;
    }
    ~Test() {
        cout << "Destroyed " << id << endl;
    }
};

int main() {
    Test x = Test(1);
    x = Test(2);

    cout << x.id << endl;
    return 0;
}

我本来期望的输出是:

1:Created 1
2 Destroyed 1:?(这是我不确定的那个,因为网站暗示如果对象被另一个“替换”而不是超出范围,则不会调用此析构函数)
3:Created 2对象 2“替换”对象 1,因为它被分配给 x
4:2打印出的对象 2 的 id 值
5:Destroyed 2对象 2 超出范围时被销毁

相反,我得到了以下输出:

Created 1
Created 2
Destroyed 2
2
Destroyed 2

这对我来说真的没有意义。

使用调试器,Created 2并且Destroyed 2x = Test(2);调用该行时都显示如果我们只是分配x给对象 2,为什么会立即调用它的析构函数?这是下一部分。

其次,由于对象 2 的析构函数已被调用,我们可以假设它已被销毁。的下一个输出2似乎与此相矛盾,因为它表明它x仍然持有对象 2(预期,但与其析构函数的调用相矛盾)。

我不太确定为什么会这样。

最后,Destroyed 2输出。如果我们没有更早地看到这一点,这将是有道理的。对象 2 存储在 中x,因此当它超出范围时会调用析构函数。

出于某种原因,我们调用了两次析构函数,对象 1 被对象 2 的赋值“覆盖”,x从不调用其析构函数,而是我们刚刚创建的对象的析构函数调用了其析构函数。

所以......这总结了一个由两部分组成的问题:

1:为什么会发生这种奇怪的行为,是否有任何合乎逻辑的原因?
2:通过赋值用另一个对象(对象2)“覆盖”一个对象(例如对象1)是否会导致其析构函数(在这种情况下是对象1的析构函数)被调用?

提前致谢。

弗朗索瓦·安德里厄

使用调试器,当行 x = Test(2); 时,Created 2 和 Destroyed 2 都会显示;叫做。如果我们只是将 x 分配给对象 2,为什么会立即调用它的析构函数?这是下一部分。

该行x = Test(2);首先Test使用构造函数参数创建 a 2这就是产生Created 2. Test然后将这个无名分配给x它,给出x.id值 2。Test然后在表达式的末尾销毁无名,产生“Destroyed 2”。

其次,由于对象 2 的析构函数已被调用,我们可以假设它已被销毁。2 的下一个输出似乎与此矛盾,因为它表明 x 仍然持有对象 2(预期,但与其析构函数的调用相矛盾)。

正如这个答案的第一部分所表达的那样,它不是x被破坏,而是临时的Temp. x.id仍然有效并将产生它的新值 2。

最后输出Destroyed 2。如果我们没有更早地看到这一点,这将是有道理的。对象 2 存储在 x 中,因此当它超出范围时会调用析构函数。

x在函数结束销毁时会发生这种情况它的id值被之前的赋值更改为 2,因此它产生“Destroyed 2”。

1:为什么会发生这种奇怪的行为,是否有任何合乎逻辑的原因?

这可能不是您期望的行为,但并不奇怪。我希望这个答案能帮助你理解它为什么会发生。

2:通过赋值用另一个对象(对象 2)“覆盖”一个对象(例如对象 1)是否会导致其析构函数(在本例中为对象 1 的析构函数)被调用?

分配给一个对象不会破坏它。它用一个新的值替换它的值,从这个意义上说,它“破坏”了它以前帮助,但实际的对象实例没有被破坏,也不涉及析构函数。

编辑:看来您可能担心资源泄漏。由于没有资源被管理,Test不会有泄漏,编译器生成的成员将表现良好。如果您的类确实管理资源(通常以动态分配内存的形式),那么您将需要应用3/5/0 规则值得注意的是,您需要自己实现赋值运算符,以便它清理任何以前持有的资源。仅仅实现析构函数是不够的,因为它不涉及赋值。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

C ++:调用了错误的析构函数

来自分类Dev

C ++:析构函数在对象范围之外被调用?

来自分类Dev

C ++的boost :: python包装对象的析构函数调用

来自分类Dev

C ++:删除对象而不调用析构函数

来自分类Dev

C ++的boost :: python包装对象的析构函数调用

来自分类Dev

C ++中的析构函数直接调用

来自分类Dev

析构函数在C ++中调用向量

来自分类Dev

C ++中的析构函数直接调用

来自分类Dev

C ++意外的析构函数调用

来自分类Dev

C ++析构函数未调用

来自分类Dev

从对象原因到此类的调用析构函数的c ++ std :: thread调用方法

来自分类Dev

什么时候在C ++中调用要调用的对象的析构函数?

来自分类Dev

为什么在调用luaL_error时未调用C ++对象析构函数?

来自分类Dev

什么时候在C ++中确切地调用了一个类的析构函数?

来自分类Dev

C ++-析构函数何时调用已使用但未分配的对象?

来自分类Dev

什么时候在堆中的对象上调用C ++析构函数?

来自分类Dev

C ++为什么在堆栈中构造完对象后立即调用析构函数?

来自分类Dev

C ++调用析构函数并不会真正从内存中删除对象

来自分类Dev

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

来自分类Dev

C ++-析构函数何时调用已使用但未分配的对象?

来自分类Dev

什么时候在堆中的对象上调用C ++析构函数?

来自分类Dev

C#,删除带有子线程的对象时,GC没有调用析构函数

来自分类Dev

C ++为什么在堆栈中构造完对象后立即调用析构函数?

来自分类Dev

C ++析构函数是否总是或仅有时调用数据成员析构函数?

来自分类Dev

C ++。在析构函数中调用虚拟成员函数

来自分类Dev

C ++析构函数比创建的构造函数破坏更多的对象

来自分类Dev

为什么在构造时调用C ++类的析构函数?

来自分类Dev

您是否在C ++中的析构函数中调用delete?

来自分类Dev

通过基本指针的C ++显式析构函数调用

Related 相关文章

  1. 1

    C ++:调用了错误的析构函数

  2. 2

    C ++:析构函数在对象范围之外被调用?

  3. 3

    C ++的boost :: python包装对象的析构函数调用

  4. 4

    C ++:删除对象而不调用析构函数

  5. 5

    C ++的boost :: python包装对象的析构函数调用

  6. 6

    C ++中的析构函数直接调用

  7. 7

    析构函数在C ++中调用向量

  8. 8

    C ++中的析构函数直接调用

  9. 9

    C ++意外的析构函数调用

  10. 10

    C ++析构函数未调用

  11. 11

    从对象原因到此类的调用析构函数的c ++ std :: thread调用方法

  12. 12

    什么时候在C ++中调用要调用的对象的析构函数?

  13. 13

    为什么在调用luaL_error时未调用C ++对象析构函数?

  14. 14

    什么时候在C ++中确切地调用了一个类的析构函数?

  15. 15

    C ++-析构函数何时调用已使用但未分配的对象?

  16. 16

    什么时候在堆中的对象上调用C ++析构函数?

  17. 17

    C ++为什么在堆栈中构造完对象后立即调用析构函数?

  18. 18

    C ++调用析构函数并不会真正从内存中删除对象

  19. 19

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

  20. 20

    C ++-析构函数何时调用已使用但未分配的对象?

  21. 21

    什么时候在堆中的对象上调用C ++析构函数?

  22. 22

    C#,删除带有子线程的对象时,GC没有调用析构函数

  23. 23

    C ++为什么在堆栈中构造完对象后立即调用析构函数?

  24. 24

    C ++析构函数是否总是或仅有时调用数据成员析构函数?

  25. 25

    C ++。在析构函数中调用虚拟成员函数

  26. 26

    C ++析构函数比创建的构造函数破坏更多的对象

  27. 27

    为什么在构造时调用C ++类的析构函数?

  28. 28

    您是否在C ++中的析构函数中调用delete?

  29. 29

    通过基本指针的C ++显式析构函数调用

热门标签

归档