【问题标题】:Why is the destructor called after assignment?为什么在赋值后调用析构函数?
【发布时间】:2017-04-24 19:05:09
【问题描述】:

为什么在mystring = "Hello, there!"; 行之后在这里调用析构函数 它还没有超出范围。我肯定错过了一些 C++ 的怪癖!

我知道那一行调用了默认的拷贝构造函数,析构函数总是在拷贝构造函数返回后调用吗?

顺便说一句,我使用的是 C++03,还没有 C++11。

编辑:另外请注意,我知道以下程序导致的双重删除。我在这里做实验。只是想引起您的注意。

class MyString
{
private:
    char* mystring;
    int m_length;
public:

    MyString(const char* str="")
    {
        assert(str);
        m_length = strlen(str) + 1;
        mystring = new char[m_length];
        for (int i = 0; i < m_length; ++i)
            mystring[i] = str[i];
        mystring[m_length-1] = '\0';
    }

    ~MyString()
    {
        delete[] mystring;
    }

};

int main()
{
   MyString mystring("");
   mystring = "Hello, there!";
   cout << "Destructor not yet called ";
}

【问题讨论】:

  • 您在运行调试器时得出了什么结论?
  • 编译器生成隐式复制赋值运算符。您的对象是从编译器创建的临时对象中分配的(因为您有一个非显式的单参数构造函数(又名转换构造函数));它是那个被破坏的时间对象。其次,你的程序有问题
  • 我肯定错过了 C++ 的一些怪癖! -- 不仅仅是你所缺少的“怪癖”。该程序产生双重删除错误{MyString m1; MyString m2=m1;}
  • @svasa -- 阅读复制构造函数和赋值运算符。
  • 阅读Rule of Three

标签: c++ c++03


【解决方案1】:

由于您的类没有赋值运算符,它采用字符串文字 mystring = "Hello, there!"; 被转换为 3 部分操作。

  • 首先它必须从字符串文字构造一个临时对象。

  • 然后,它使用该临时值并将其与编译器为类生成的默认复制(C++11 前)/移动(C++11 后,如果未删除)赋值运算符一起使用。

  • 然后它必须销毁它创建的临时对象。这就是为什么您会在该表达式的末尾看到对析构函数的调用。


请注意,由于临时对象在之后被销毁

mystring = "Hello, there!";

mystring 持有的指针现在已被删除,您无法再访问它。当它被销毁时也会导致双重删除,这是未定义的行为并且会导致并发症。

【讨论】:

  • 我没看错,那myString一共被删除了两次,mystring建好后就已经没用了。
  • Then it has to destroy the temporary object that it created - 这是我缺少的部分。谢谢。还有一个问题,编译器总是删除它在使用复制构造函数时创建的临时对象?
  • @tobi303 myString 有双重删除并没有错,但似乎 OP 知道这一点,所以我没有提及。
  • @svasa 是的,编译器在表达式中生成的所有临时对象都在完整表达式的末尾被销毁。
  • Err... 正在删除字符串文字,即使是已定义的行为?
猜你喜欢
  • 2020-10-29
  • 2018-05-07
  • 2019-11-16
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 2021-08-04
  • 1970-01-01
  • 2016-06-25
相关资源
最近更新 更多