我正在尝试使用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";
}
# 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}}永远不会被破坏。正如我在代码中提到的,我可以在重新分配之前手动调用析构函数,但我不确定这是不是一个好主意。是,如果没有,你有什么建议?还有吗
在实际代码中,我正在使用二叉树,我认为将节点作为向量的成员并指向彼此的索引到向量中会很有趣(让我获得连续的内存缓存优势,32位索引而不是64位指针,以及不同的东西)。但最终,我需要对树进行一些操作,这意味着移动/删除元素,所以我希望调用析构函数来移除元素(我将使用1
或其他东西来跟踪漏洞在矢量)。
答案 0 :(得分: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";
}
};
分配不破坏现有对象,它分配。您可以使用更简单的案例重现这一点
int main() {
S s1(1);
s1 = S(2); // assignment, not destruction/construction. same idea
}
如果您的对象拥有某些资源,您会发现赋值运算符对析构函数和复制构造函数执行类似的操作。通过添加移动操作,您可以read about the rule of 3 here扩展为规则5 。