假设我有一个类型为my_object
的向量,其大小为3,我想从我的向量中获取3个元素,将它们存储在引用中
然后我想使用std::remove_if()
1>使用std::remove
和element_1以及element_2删除和删除element_3
以下是my_object
:
class my_object {
public:
my_object(int num);
bool exists() const;
private:
int num;
};
my_object::my_object(int num) : num(num) {}
bool my_object::exists() { return num == 1; }
以下是main
:
std::vector<my_object> my_vector;
int main() {
my_object e1(2);
my_object e2(2);
my_object e3(1); // i.e exists() will return true in lambda
my_vector.push_back(e1);
my_vector.push_back(e2);
my_vector.push_back(e3);
const auto& element_1 = my_vector.at(0);
const auto& element_2 = my_vector.at(1);
const auto& element_3 = my_vector.at(2);
auto lambda = [](auto& src) { return src.exists() };
std::erase(std::remove_if(b, e, lambda), e); // remove_if for element_3
std::erase(std::remove(b, e, element_1), e);
std::erase(std::remove(b, e, element_2), e);
return 0;
}
非常奇怪的是,当我通过引用声明element_1,element_2,element_3而不是擦除没有正确完成并且大小不会减小到0,但是当我写const auto
时没有&
然后它完全正常,任何人都可以向我解释这种奇怪的行为吗?
答案 0 :(得分:2)
折扣擦除方法,这些引用就是:对容器中的对象的引用。一旦remove
或remove_if
在进行序列的过程中执行了他们的任务移动分配,那些引用仍然指的是相同的元素,但这些插槽的占用者是:
我不会潜入std::remove
,而是。看看std::remove_if
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v = { 1,2,3,4,5 };
const auto& a1 = v.at(0);
const auto& a2 = v.at(2);
const auto& a3 = v.at(4);
std::cout << a1 << ' ' << a2 << ' ' << a3 << '\n';
std::remove_if(v.begin(), v.end(), [](const auto& x) { return x == 3; });
std::cout << a1 << ' ' << a2 << ' ' << a3 << '\n';
}
<强>输出强>
1 3 5
1 4 5
正如您所看到的,std::remove_if
的功能描述符合您在代码中看到的内容。已移除3
元素,并将4
元素移动分配到其位置。你在这里看不到的是5
元素被移动分配到4
的位置,你现在看到的5
值恰好来自插槽其中5
是。该标准表示该对象是“有效的”,但具有“未指定”的值。我们可以通过确保移动来源的移动来源实际上是“无效的”(据我们所关注)来验证。修改我们的原始程序给了我们这个:
#include <iostream>
#include <vector>
#include <algorithm>
struct S
{
S(int n) : value(n), isvalid(true)
{
}
S(const S& s) : value(s.value), isvalid(true)
{
}
S(S&& s) : value(s.value), isvalid(true)
{
s.isvalid = false;
}
S& operator =(S&& s)
{
value = s.value;
isvalid = s.isvalid;
s.isvalid = false;
return *this;
}
int value;
bool isvalid;
};
std::ostream& operator <<(std::ostream& outp, const S& s)
{
outp << s.value << '(' << std::boolalpha << s.isvalid << ')';
return outp;
}
int main()
{
std::vector<S> v = { 1,2,3,4,5 };
const auto& a1 = v.at(0);
const auto& a2 = v.at(2);
const auto& a3 = v.at(4);
std::cout << a1 << ' ' << a2 << ' ' << a3 << '\n';
std::remove_if(v.begin(), v.end(), [](const auto& x) { return x.value == 3; });
std::cout << a1 << ' ' << a2 << ' ' << a3 << '\n';
}
<强>输出强>
1(true) 3(true) 5(true)
1(true) 4(true) 5(false)
底线:您的引用仍指向之前的相同插槽,但元素已经(a)移动分配给其他内容,或(a)不再包含指定内容。在执行容器修改时使用对容器内容的引用时要小心。
我保留对std::erase
来电的评论,因为我根本不知道你在做什么。据我所知,这甚至都不是标准库中的一个函数(这不是我第一次错过一个新函数,但是对于cppreference的挖掘没有产生任何结果,所以请考虑它的价值)。