rspec/rules/S6165/cfamily/rule.adoc

62 lines
1.8 KiB
Plaintext

== Why is this an issue?
Removing elements with a specific value or that follow a given predicate from a container is a common task. Before {cpp}20, this was not straightforward. The way to do it had to depend on the type of your container.
For sequence containers, you would end up following what is called the _erase-remove idiom_:
* Call ``++std::remove++`` or ``++std::remove_if++`` with, as parameters, the container and the criterion to fulfill
* Call the container member function ``++erase++`` on the result
For associative containers, you would have no other option than looping through all the elements by hand.
However, {cpp}20 introduced two new methods: ``++std::erase++`` (for sequence containers only) and ``++std::erase_if++`` which erase all elements equal to a value or that satisfy a given predicate.
This rule raises an issue when ``++std::erase++`` or ``++std::erase_if++`` could be used to simplify the code.
=== Noncompliant code example
[source,cpp]
----
void removeZeros(std::vector<int> &v) {
v.erase(std::remove(v.begin(), v.end(), 0), v.end()); // Noncompliant
}
void removeOddNumbers(std::vector<int> &v) {
v.erase(std::remove_if(v.begin(), v.end(), [](auto i) { return i%2 == 0; }), v.end()); // Noncompliant
}
void removeOddNumbers(std::unordered_map<std::string, int> &m) {
auto it = m.begin();
while (it != m.end()) { // Noncompliant
if (it->second % 2 == 0) {
it = m.erase(it);
} else {
++it;
}
}
}
----
=== Compliant solution
[source,cpp]
----
void removeZeros(std::vector<int> &v) {
std::erase(v, 0);
}
void removeOddNumbers(std::vector<int> &v) {
std::erase_if(v, [](auto i) { return i%2 == 0; });
}
void removeOddNumbers(std::unordered_map<std::string, int> &m) {
std::erase_if(m, [](auto item) { return item.second % 2 == 0; });
}
----