使用 std::replace 时,有没有办法调用被替换元素的析构函数?
Is there a way to call the destructor of a replaced element when using std::replace?
我有一个对象向量,我想用其中的一个元素替换另一个元素。
使用 std::replace 似乎很合适,所以我试了一下。
虽然我担心被替换元素的下落,所以我做了一些测试:
#include <iostream>
#include <vector>
#include <algorithm>
class A {
public:
A(const int ii) : i(ii) { std::cout << "Constructor " << i << std::endl;}
~A(){std::cout << "Destructor " << i << std::endl;}
auto operator ==(const A& a){ return i == a.i;}
int i;
};
int main()
{
std::vector<A> v;
v.reserve(4);
v.emplace_back(10);
v.emplace_back(20);
v.emplace_back(40);
v.emplace_back(30);
for(const auto& elt : v){
std::cout << elt.i << ' ';
}
std::cout << std::endl;
std::replace(v.begin(), v.end(), v[2], A(25));
for(const auto& elt : v){
std::cout << elt.i << ' ';
}
std::cout << "End of program" << std::endl;
}
向量的第三个元素被替换,但如您所见,替换后的对象析构函数未被调用:
Constructor 10
Constructor 20
Constructor 40
Constructor 30
10 20 40 30
Constructor 25
Destructor 25
10 20 25 30 End of program
Destructor 10
Destructor 20
Destructor 25
Destructor 30
由于每个编译器的行为都相同,我想这是有意为之的,但是在这种情况下有没有办法调用析构函数?
测试示例:
https://godbolt.org/z/YTaKcrTEn
谢谢!
没有。 replace
使用赋值,赋值需要一个 live 对象。
如果你的类型有一个有意义的析构函数(即:规则 5),并且你的类型是可赋值的,那么赋值应该有效地等同于调用析构函数然后在对象上进行放置-new
.
我想你可能对析构函数的作用有误解。
析构函数获取一个对象,并将其变成“非对象”(只是原始内存)。这与构造函数相反,构造函数获取原始内存并将其转换为对象。
在您的代码中,您为对象分配了一个新值(通过 std::replace
)。这不会创建新对象,也不会破坏任何对象 - 因此没有构造函数或析构函数调用。
从 cppreference 到 std::replace
:
Because the algorithm takes old_value
and new_value
by reference, it
can have unexpected behavior if either is a reference to an element of
the range [first, last)
.
因此,这是错误的:
std::replace(v.begin(), v.end(), v[2], A(25));
确实,我们不能像这里那样选择 old_value
作为对 v[2]
的引用。请考虑:
A to_replace{v[2]}; // copy
std::replace(v.begin(), v.end(), to_replace, A(25));
您也可以在不使用附加变量的情况下强制复制(如 Staz 所建议的):
std::replace(v.begin(), v.end(), A{v[2]}, A(25));
我有一个对象向量,我想用其中的一个元素替换另一个元素。 使用 std::replace 似乎很合适,所以我试了一下。
虽然我担心被替换元素的下落,所以我做了一些测试:
#include <iostream>
#include <vector>
#include <algorithm>
class A {
public:
A(const int ii) : i(ii) { std::cout << "Constructor " << i << std::endl;}
~A(){std::cout << "Destructor " << i << std::endl;}
auto operator ==(const A& a){ return i == a.i;}
int i;
};
int main()
{
std::vector<A> v;
v.reserve(4);
v.emplace_back(10);
v.emplace_back(20);
v.emplace_back(40);
v.emplace_back(30);
for(const auto& elt : v){
std::cout << elt.i << ' ';
}
std::cout << std::endl;
std::replace(v.begin(), v.end(), v[2], A(25));
for(const auto& elt : v){
std::cout << elt.i << ' ';
}
std::cout << "End of program" << std::endl;
}
向量的第三个元素被替换,但如您所见,替换后的对象析构函数未被调用:
Constructor 10
Constructor 20
Constructor 40
Constructor 30
10 20 40 30
Constructor 25
Destructor 25
10 20 25 30 End of program
Destructor 10
Destructor 20
Destructor 25
Destructor 30
由于每个编译器的行为都相同,我想这是有意为之的,但是在这种情况下有没有办法调用析构函数?
测试示例: https://godbolt.org/z/YTaKcrTEn
谢谢!
没有。 replace
使用赋值,赋值需要一个 live 对象。
如果你的类型有一个有意义的析构函数(即:规则 5),并且你的类型是可赋值的,那么赋值应该有效地等同于调用析构函数然后在对象上进行放置-new
.
我想你可能对析构函数的作用有误解。
析构函数获取一个对象,并将其变成“非对象”(只是原始内存)。这与构造函数相反,构造函数获取原始内存并将其转换为对象。
在您的代码中,您为对象分配了一个新值(通过 std::replace
)。这不会创建新对象,也不会破坏任何对象 - 因此没有构造函数或析构函数调用。
从 cppreference 到 std::replace
:
Because the algorithm takes
old_value
andnew_value
by reference, it can have unexpected behavior if either is a reference to an element of the range[first, last)
.
因此,这是错误的:
std::replace(v.begin(), v.end(), v[2], A(25));
确实,我们不能像这里那样选择 old_value
作为对 v[2]
的引用。请考虑:
A to_replace{v[2]}; // copy
std::replace(v.begin(), v.end(), to_replace, A(25));
您也可以在不使用附加变量的情况下强制复制(如 Staz 所建议的):
std::replace(v.begin(), v.end(), A{v[2]}, A(25));