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

标签 c++ memory vector destructor

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

代码

#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";
}

输出

# 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

问题

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

连接到我真正想要的东西

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

最佳答案

分配给 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";
    }
};

分配不会破坏现有对象,它分配给它。您可以使用更简单的案例重现此内容

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

如果您的对象拥有某些资源,您会发现赋值运算符对析构函数和复制构造函数执行类似的操作。你可以read about the rule of 3 here它通过添加移动操作扩展到 5 的规则

关于c++ - std::vector 在重新分配时不调用析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50357280/

相关文章:

c++ - 无法写入 AllocConsole()

c++ - wxWidgets 有某种垃圾收集器吗?

c++ - 如何加载自定义字体以便我可以在 DirectX 中使用它们?

multithreading - 如何从结构向量中生成线程以从向量中的每个结构运行 impl fn?

java - 如何从 vector 中获取特定索引的值?

C++:保存实体列表 vector 与集合的最佳方式

C++ 类模板构造函数继承与指针

c++ - 如果头文件被更改然后恢复,如何停止/欺骗 cmake 不重建?

c++ - 如何将整数 push_back 为字符串?

java - 在java中存储二维数组的最小方式