基于 C++ 堆栈的构造函数/析构函数未按预期工作

标签 c++

我无法理解为什么以下代码没有按照我期望的方式构造和破坏我创建的两个对象:

#include <iostream>

class MyClass {

    int myVar;

public:
    MyClass(int x) {
        myVar = x;
        std::cout << "constructing " << myVar << ", " << (long)this << std::endl;
    }

    ~MyClass() {
        std::cout << "destructing " << myVar << ", " << (long)this << std::endl;
    }
};

int main(int argc, const char * argv[])
{
    MyClass a = MyClass(1);
    a = MyClass(2);
    return 0;
}

我认为在 main 中我首先创建一个值为 1 的对象,然后创建一个值为 2 的新对象。每个对象都被构建和销毁,因此我希望看到以下输出:

constructing 1, 3456
constructing 2, 6789
destructing 1, 3456
destructing 2, 6789

但是,我明白了:

constructing 1, 3456
constructing 2, 6789
destructing 2, 6789   <- note the "2"
destructing 2, 3456

更新:我添加了对象地址 (this) 的输出,以便人们可以更好地了解哪个对象做了什么。

当我改用“new MyClass”时,我不会遇到这种奇怪的效果。

造成这种情况的原因是什么?了解我的目标后,避免将来出现类似错误的正确方法是什么?

虽然这个示例看起来无害,但我遇到了代码崩溃,因为我在构造函数中分配了其他对象并在析构函数中释放了它们。这确实导致在对象仍在使用时释放对象。

结论

既然我所有的问题都得到了解答,那么让我总结一下:

  1. 在上面的示例中,我使用的是“myVar”,它甚至没有显示导致我提出这个问题的问题。对此我深表歉意。
  2. 我在代码中遇到的实际问题是我没有使用简单的 int var,而是在析构函数中使用“new”创建的数组,并在析构函数中使用 delete 释放。这样,数组将被删除两次,导致我的程序中出现不正确的数据。
  3. 解决方法是不使用指向数组的简单指针,而是使用引用计数指针,这样,当它被赋值运算符复制时,它会增加引用计数,从而防止过早释放它。
  4. 总的来说,我在这里展示的效果没有什么危险——它不会像我的印象那样损坏任何东西。危险的部分是我没有使用引用计数指针。

最佳答案

a = MyClass(2); 行不会调用析构函数,它会调用您尚未实现的赋值运算符 (MyClass::operator=) ,所以编译器为你提供了一个——它不会“打印”任何东西,所以你看不到。

你得到 destrucing 2 两次的原因是 a = MyClass(2); 行之后,临时 MyClass(2) 对象被销毁。然后在 main 结束时,变量 a 被销毁,因为 myVar 现在是 2,它再次打印 2。

关于基于 C++ 堆栈的构造函数/析构函数未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18233825/

相关文章:

c++ - C++实现合并排序的运行时错误

c++ - gdb 导入的崩溃/退出时间的进程转储?

c++ - OpenCV C++ cv::convexityDefects 错误

c# - 将窗口的 SetParent() 设置为 SHELLDLL_DefView 是否安全?

c++ - 如何使用 C 终止远程计算机上的进程?

c++ - PostMessage 只能工作一次?

c++ - 回退到复制构造函数不起作用?

c++ - 用方法替换包装智能指针

c++ - boost::uint64_t 的字符串因 lexical_cast 和 stringsteam 而失败

C++:牛顿拉夫森和重载函数