Using erase-remove idiom on non-unique collections - c++

#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
enum class En{A, B};
std::vector<En> vec{En::A, En::B, En::A, En::B, En::A, En::B, En::A};
for(const auto& i : vec) std::cout << int(i) << ", ";
std::cout << std::endl;
vec.erase(std::remove(std::begin(vec), std::end(vec), vec.front()),
std::end(vec));
for(const auto& i : vec) std::cout << int(i) << ", ";
std::cout << std::endl;
return 0;
}
Ideone: http://ideone.com/NTPVyE
Prints:
0, 1, 0, 1, 0, 1, 0,
1, 0, 0, 0,
Why is this happening? Shouldn't only the first element of the vector be removed?
I suppose std::remove doesn't stop at the first element, but runs through the whole vector. Is there any way I can use the erase-remove idiom on collections with non-unique elements?

The third argument to std::remove is a const reference. You are changing the value of the element refered to as you move elements around, leading to undefined behaviour.
This would be well behaved:
auto elem = vec.front(); // copy front element
vec.erase(std::remove(std::begin(vec), std::end(vec), elem),
std::end(vec));
Output:
1, 1, 1,

Related

C++ Vector Sorts

I am working with a vector in Codefights for the "almostIncreasingSequence" challenge. Is there a way to track how many "steps" a sort method takes when so I can set a simple counter/flag to check against if the sort passes a predefined threshold?
Yes there is. You can use a custom comparison function with std::sort as follows:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> myVector { 2, 8, 5, 9, 3, 7, 1, 4, 6, 0 };
int counter = 0;
std::sort(myVector.begin(), myVector.end(), [&counter](int lhs, int rhs) {
counter++;
return lhs < rhs;
});
std::cout << "Steps: " << counter << std::endl;
for(auto e : myVector)
std::cout << e << ' ';
std::cout << std::endl;
return 0;
}

Maximum decreasing prefix with iterators

I am writing next permutation algorithm in C++.
It is forbidden to use for and while (we are supposed to do everything with iterators only).
The first step of the algorithm is to get maximum non-increasing suffix. I am strucked, because I don't understand how to find something in vector by condition using only iterators.
You can use std::find or std::for_each defined in algorithm e.g. example using C++14:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v{0,1,2,3,5,7};
auto f = std::find(std::begin(v), std::end(v), 5);
if (f != std::end(v)) {
std::cout << "found element 5" << std::endl;
}
std::for_each(
std::begin(v),
std::end(v),
[](int n) {
if (n == 5) {
std::cout << "found element 5" << std::endl;
}
}
);
}

Checking if a sequence container is contiguous in memory

Is there a way to check if a sequence container is contiguous in memory? Something like:
#include <iostream>
#include <vector>
#include <deque>
#include <array>
int main()
{
std::cout << std::boolalpha;
std::cout << is_contiguous<std::vector<int>>::value << '\n' // true
std::cout << is_contiguous<std::deque<int>>::value << '\n'; // false
std::cout << is_contiguous<std::array<int, 3>>::value << '\n'; // true
}
Clarification
This question is referring to type traits, rather than the properties of a specific instance of a type.
No, there is not compiletime trait for this.
The draft C++1z Standard defines contiguity as a runtime property of an iterator range. Note there is no compiletime std::contiguous_iterator_tag corresponding to this iterator category.
24.2 Iterator requirements [iterator.requirements]
24.2.1 In general [iterator.requirements.general]
5 Iterators that further satisfy the requirement that, for integral
values n and dereferenceable iterator values a and (a + n), *(a + n)
is equivalent to *(addressof(*a) + n), are called contiguous
iterators. [ Note: For example, the type “pointer to int” is a
contiguous iterator, but reverse_iterator<int *> is not. For a valid
iterator range [a,b) with dereferenceable a, the corresponding range
denoted by pointers is [addressof(*a),addressof(*a) + (b - a)); b
might not be dereferenceable. — end note ]
One way to test for this at runtime would be
#include <array>
#include <deque>
#include <list>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
template<class I>
auto is_contiguous(I first, I last)
{
auto test = true;
auto const n = std::distance(first, last);
for (auto i = 0; i < n && test; ++i) {
test &= *(std::next(first, i)) == *(std::next(std::addressof(*first), i));
}
return test;
}
int main()
{
auto l = std::list<int> { 1, 2, 3 };
auto m = std::map<int, int> { {1, 1}, {2,2}, {3,3} };
auto u = std::unordered_multiset<int> { 1, 1, 1 };
auto d = std::deque<int>(4000);
int c[] = { 1, 2, 3 };
auto a = std::array<int, 3> {{ 1, 2, 3 }};
auto s = std::string {"Hello world!"};
auto v = std::vector<int> { 1, 2, 3, };
std::cout << std::boolalpha << is_contiguous(l.begin(), l.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(m.begin(), m.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(u.begin(), u.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(d.begin(), d.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(d.begin(), d.begin() + 1000) << "\n";
std::cout << std::boolalpha << is_contiguous(std::begin(c), std::end(c)) << "\n";
std::cout << std::boolalpha << is_contiguous(a.begin(), a.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(s.begin(), s.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(v.begin(), v.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(v.rbegin(), v.rend()) << "\n";
}
Live Example. This prints false for the list, map and unordered_multimap, and true for the C-array, and the std::array, string and vector. It prints true for small subranges within a deque and false for large subranges. It also prints false for an iterator range consisting of reverse iterators.
UPDATE: as commented by #T.C. the original N3884 proposal did have a
struct contiguous_iterator_tag : random_access_iterator_tag {};
so that tag-dispatching on iterator categories would not break. However, this would have broken non-idiomatic code with class template specializations on random_access_iterator_tag. The current draft hence does not contain a new iterator category tag.
No. The C++ Standard guarantees there are no false negatives. (i.e., std::vector, std::string, std::array, and basic arrays are promised to be stored contiguously).
However, the C++ Standard doesn't guarantee there are no false positives.
int main() {
std::unique_ptr<Node> n1(new Node);
std::unique_ptr<Node> n2(new Node);
n1->next = n2; // n1 and n2 might be contiguous, but might not be
}
Thus, your type trait could be wrong some of the time. If it's wrong some of the time, it's not a type trait; rather, it's an instance trait.
No.​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

Remove last 5 elements of a map

I want to remove last 5 elements from a std::map.
One way is:
for(int i=0; i < 5; i++)
{
map<string, LocationStruct>::iterator it = myLocations.end();
it--;
myLocations.erase(it);
}
Is there a good way to do that without looping?
Thanks,
a compilable demo of one way to do it. Note that because map iterators are not random access iterators, there's likely to be a loop involved under the covers during the call to std::prev() anyway.
#include <iostream>
#include <map>
#include <string>
using namespace std::string_literals;
std::map<int, std::string> m = {
{ 0, "zero"s },
{ 1, "one"s },
{ 2, "two"s },
{ 3, "three"s },
{ 4, "four"s },
{ 5, "five"s }
};
auto main() -> int
{
for (const auto& entry : m) {
std::cout << entry.first << ", " << entry.second << std::endl;
}
// erase operation here
m.erase(std::prev(m.end(), 5), m.end());
std::cout << "\nafter erase \n\n";
for (const auto& entry : m) {
std::cout << entry.first << ", " << entry.second << std::endl;
}
return 0;
}
expected output:
0, zero
1, one
2, two
3, three
4, four
5, five
after erase
0, zero
You can use the std::prev function to do navigation for you:
m.erase(prev(m.end(), 5), m.end());
Use range erase
auto i = m.begin();
std::advance(i, (m.size() - 5) );
m.erase( i, m.end() );
As far as I know, std::map has normal access iterator, so you have to traverse to last element every time to erase it from memory.

STL correct use of find_if() to print out odd numbers

How can I possibly make use of the find_if algorithm from STL to find and print out odd numbers from a vector?
Let me just give you an example of what I'm on about:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool isOdd(int x)
{
return x%2 == 0;
}
int main(void)
{
int tab[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> myVec(tab, tab + sizeof(tab)/sizeof(tab[0]));
vector<int>::iterator it;
// Printing out all numbers
cout << "Vector contains the following numbers: " << endl;
for(it = myVec.begin(), it != myVec.end(), ++it)
{
cout << *it << ' ';
}
// An unsuccessful attempt to print out odd numbers while using find_if and while loop
vector<int>::iterator bound = find_if(myVec.begin(), myVec.end(), isOdd);
while(bound != myVec.end())
{
cout << *bound << ' ';
}
}
What is wrong with while loop? I guess it's the core problem of my code.
I'm assigning whatever the find_if function will return to the iterator, and then I simply can't figure out how to cherry-pick odd values from the vector ;(
The problem is that you are not advancing the iterator in your loop:
while(bound != myVec.end())
{
cout << *bound << ' ';
bound = find_if(bound+1, myVec.end(), isOdd);
}
In C++11 you can use std::next(bound) instead of bound+1.
Also, your isOdd returns true when the number is even. It should be
bool isOdd(int x)
{
return x%2 != 0;
}
Demo.
Just adding that for this use I'd just use std::copy_if:
std::copy_if(myVec.begin(), myVec.end(),
std::ostream_iterator<int>(std::cout, " "), isOdd);
Similarly, the first for loop in your code (and those should be semicolons, not commas) can be replaced with std::copy:
std::copy(myVec.begin(), myVec.end(), std::ostream_iterator<int>(std::cout, " "));
Demo.