std :: vector在重新分配时不调用析构函数

Ben*_*Ben 1 c++ memory destructor vector

我正在尝试使用a std::vector来保存一些S实例.但是,当我重新分配向量的成员时,不会在前一个租户上调用析构函数:

#include <iostream>
#include <vector>

struct S {
    int index_;
    S(int index) : index_(index) {
        std::cout << "Calling S " << index_ << " constructor\n";
    }
    S(const S& other) : index_(other.index_) {
        std::cout << "Calling S " << index_ << " copy constructor\n";
    }
    ~S() {
        std::cout << "Calling S " << index_ << " destructor\n";
    }
};


int main()
{
    std::vector<S> v;
    v.reserve(10); // Let's not worry about copy constructors
    std::cout << "# Created vector\n";
    v.emplace_back(0);
    v.emplace_back(1);
    v.emplace_back(2);
    std::cout << "# Replacing\n";
    v[1] = S(3); // This doesn't destruct S(1) that was here

    // I can manually call the destructor before I reassign but is that
    // something I should do()?
    // v[1].~S();

    std::cout << "# End scope\n";
}
Run Code Online (Sandbox Code Playgroud)

产量

# Created vector
Calling S 0 constructor
Calling S 1 constructor
Calling S 2 constructor
# Replacing
Calling S 3 constructor
Calling S 3 destructor
# End scope
Calling S 2 destructor
Calling S 3 destructor
Calling S 0 destructor
Run Code Online (Sandbox Code Playgroud)

因此看起来S(1)位置1永远不会被破坏.正如我在代码中提到的,我可以在重新分配之前手动调用析构函数,但我不确定这是不是一个好主意.是,如果没有,你有什么建议?还有,是吗?

与我真正想要的联系

在真正的代码中,我正在使用二叉树,我认为将节点作为向量的成员并使用索引到向量中指向彼此会很有趣(获得连续的内存缓存优势,32位索引而不是64位指针,以及与之不同的东西).但最终,我需要对树进行一些操作,这意味着移动/删除元素,所以我希望调用析构函数来移除元素(并且我将使用std::set或者某些东西来跟踪向量中的孔).

Rya*_*ing 8

分配给vector元素将调用复制赋值运算符,而不是复制构造函数.这就是你需要的

struct S {
    int index_;
    S(int index) : index_(index) {
        std::cout << "Calling S " << index_ << " constructor\n";
    }
    S(const S& other) : index_(other.index_) {
        std::cout << "Calling S " << index_ << " copy constructor\n";
    }

    // added
    S& operator=(const S& other) {
        if (this == &other) { return *this; }
        std::cout << "Calling S " << index_ << " copy assignment\n";
        index_ = other.index_;
        return *this;
    }

    ~S() {
        std::cout << "Calling S " << index_ << " destructor\n";
    }
};
Run Code Online (Sandbox Code Playgroud)

分配不会破坏现有对象,它会分配给它.您可以使用更简单的情况重现这一点

int main() {
    S s1(1);
    s1 = S(2); // assignment, not destruction/construction. same idea
}
Run Code Online (Sandbox Code Playgroud)

如果您的对象拥有某些资源,您会发现赋值运算符对析构函数和复制构造函数执行类似的操作.您可以在此处阅读有关规则3规则,并通过添加移动操作扩展到规则5.

  • 沮丧者应该明确说明他们为什么会投票. (3认同)