【问题标题】:If std::vector reallocates objects to new memory by using move constructor then why does it have to call the destructor on the original objects?如果 std::vector 使用移动构造函数将对象重新分配到新内存,那么为什么必须在原始对象上调用析构函数?
【发布时间】:2022-06-10 18:22:14
【问题描述】:

如果你的类的移动构造函数是 noexcept,那么 std::vector 将分配新的内存,然后移动在新的内存中构造你的对象。如果它不是“noexcept”,它将复制构造它们。如果它复制构造它们,那么在释放旧缓冲区之前仍然需要销毁这些对象。但是,为什么如果对象被移动,它仍然会调用所有旧对象的析构函数。我不明白为什么这是必要的。除了一些条件检查之外,对移出对象的任何析构函数调用都不会做任何事情。您可能会争辩说“对象在技术上没有被破坏”,这是真的,但是由于该内存正在被释放,并且下次使用该内存时,唯一定义的访问对象的方法是首先构造它们,我不不明白为什么需要这样做:

struct Foo
{

    void* buffer;
    Foo() : buffer(new char[16]) {}
    Foo(Foo&& other) { buffer = other.buffer; if (other.buffer != nullptr) other.buffer = nullptr; }

    ~Foo()
    {
        if (buffer != nullptr) delete buffer;
    }
};

int main()
{

    

    Foo foo;
    Foo foo2 = std::move(foo);

    foo.~Foo(); /* NO EFFECT */

    /* BUT ASSUMING WE DIDN'T CALL THE CONSTRUCTOR, WE JUST CONSTRUCT OVER IT */
    new (&foo) Foo{};
    /* THEN THE OLD FOO CEASES TO EXIST EVEN IF THE DESTRUCTOR IS NEVER CALLED */

}

这是一个快速程序,显示 std::vector 调用旧的移出对象上的析构函数:

#include <iostream>
struct Foo
{
    
    Foo() {}
    Foo(uint32 id) {  }
    Foo(const Foo& other) 
    {
        std::cout << "Copy constructor called\n";

    }
    Foo(Foo&& other) noexcept 
    {
    
        std::cout << "Move constructor called\n";
    };

    
    ~Foo()
    {
        std::cout << "Destructor called\n";
    }
};

int main()
{
    Foo foo;
    std::vector<Foo> v;
    v.push_back(std::move(foo));
    v.push_back(std::move(foo));
    v.push_back(std::move(foo));
    v.push_back(std::move(foo));

}

【问题讨论】:

  • 因为旧对象仍然存在,需要销毁。将移动构造函数添加到语言中时,它们并没有改变析构函数的工作方式。
  • @Zebrafish 移动的对象保持未指定但有效的状态。它们必须被销毁。
  • 你的 Foos 析构函数不需要为移动的对象做一些事情,但这并不意味着一般情况下就是这样

标签: c++ destructor


猜你喜欢
  • 2020-06-05
  • 1970-01-01
  • 2017-06-11
  • 2023-04-08
  • 2013-06-02
  • 2014-08-26
  • 2018-10-25
  • 1970-01-01
  • 2021-11-25
相关资源
最近更新 更多