Is the implementation of the erase function of std::set on msvc v140 not conforming standard C++11?
According to the standard (and as mentioned here) "the erase members shall invalidate only iterators and references to the erased elements." However some code that relies on this doesn't work as expected (below an example resulting in memory leaks, actual code runs forever despite being a much smaller set).
#include <set>
#include <random>
#include <iostream>
#include <algorithm>
#define MSVC_IS_NOT_STANDARD_COMPLIANT
int main() {
// Attempt memory debugging
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_LEAK_CHECK_DF);
std::cout << "Generating numbers" << std::endl;
using Numbers = std::set<unsigned short>;
Numbers numbers;
std::mt19937_64 generator;
std::uniform_int_distribution<unsigned> distr(0, std::numeric_limits<unsigned short>::max());
for (int i = 0; i < 100000; ++i) {
numbers.emplace(distr(generator));
}
std::cout << "Determining non-primes" << std::endl;
auto is_prime = [](unsigned short n) {
if (n<3) {
return true;
}
for (unsigned i =2;i<n;++i) {
if (n % i == 0) {
return false;
}
}
return true;
};
std::vector<Numbers::const_iterator> to_remove;
for (auto it = numbers.begin(); it != numbers.end(); ){
if (!is_prime(*it)) {
#ifdef MSVC_IS_NOT_STANDARD_COMPLIANT
to_remove.emplace_back(it);
}
++it;
#else
it = numbers.erase(it);
} else {
++it;
}
#endif
}
#ifdef MSVC_IS_NOT_STANDARD_COMPLIANT
std::cout << "Removing non-primes" << std::endl;
for (auto it : to_remove) {
numbers.erase(it);
}
#endif
std::cout << "Number of primes in [0-65536]:" << numbers.size() << std::endl;
Please note that I would rather prefer that there is a bug in the actual code (I can't reproduce the same behavior with a toy example) or that I don't understand the standard.
But just in case of non conformance:
Is there an overview of the issues in standard compliance of the msvc versions?
My first thought was that this requirement was dropped in later versions of the standard and that the msvc implementation was ahead. However this requirement is still there in later versions (C++11/23.2.5.13, C++14/23.2.4.9, c++18/26.2.7.14). Given that removing entries from a set is quite common, I'm wondering what other issues the msvc implementation has (regarding the standard compliance) and how this changes over time (hoping to move to msvc 14.2 soon).