unordered_map elements disappeared after [] operation in c++ - c++

The behavior that unodered_map elements disappeared unexpectedly in the following C++ code confused me a whole lot. In the first for loop I stored the remainder of each element in time moduled by 60 and its count in unordered_map<int, int> m, in the second for loop, I printed the content in m, so far everything seems working right.
cout as following
0:1
39:1
23:1
18:1
44:1
59:1
12:1
38:1
56:2
17:1
37:1
24:1
58:1
However in the third for loop, it only printed part of elements in m,
0:1
39:1
58:1
0:1
it seems many elements in m were erased by n += m[remainder]*m[60-remainder]; operation. I was so confused by this behavior, could you please understand what is going here? Really so confused.
#include <iostream>
#include<unordered_map>
#include<vector>
using namespace std;
int main() {
vector<int> time ({418,204,77,278,239,457,284,263,372,279,476,416,360,18});
int n =0;
unordered_map<int,int> m; // <remiander,cnt>
for (auto t:time)
m[t%60]++;
for (auto [remainder,cnt]:m)
cout<<remainder<<":"<<cnt<<endl;
cout<<endl;
for (auto [remainder,cnt]:m){
cout<<remainder<<":"<<cnt<<endl;
if (remainder==0 || remainder==30)
n += cnt*(cnt-1)/2;
else
n += m[remainder]*m[60-remainder];
}
}

The third loop uses the [] operator inside the loop.
for (auto [remainder,cnt]:m){
// ...
n += m[remainder]*m[60-remainder];
unordered_map's [] invalidates all existing iterators if it results in a rehash. This includes the implicit iterators employed during range iteration.
As shown, m[remainder] cannot cause a rehash because it can only access an existing value in the unordered map, but this is not true for m[60-remainder], resulting in undefined behavior.
You just need to remove this usage of the [] operator and replace it with the equivalent find() (and, of course, correctly handling the end() value if it gets returned).

Related

How to find unique values in a vector c++

I am trying to solve a coding problem where I am to check and see if a vector has unique values and if it does then return true else false.
So Far I thought of using a nested loops where you would compare the first to the last, but I am wanted to know if C++ has anything else then doing a o(n^2) type iteration. I saw that c++ has a unique function, but that would delete the unique value.
Example 1:
Input: nums = [1,2,3,1]
Output: true
Example 2:
Input: nums = [1,2,3,4]
Output: false
std::unique checks for consecutive duplicates and moves them to the end of the range. It does not remove them from the vector. Anyhow you can make a copy. It also returns an iterator to the end of the range of unique values (that are now in the front of the vector):
#include <iostream>
#include <vector>
#include <algorithm>
bool only_unique(std::vector<int> v) {
std::sort(v.begin(),v.end());
return std::unique(v.begin(),v.end()) == v.end();
}
int main(){
std::cout << only_unique({1,2,3,1});
std::cout << only_unique({1,2,3,4});
}
If you don't want to use the additional memory you can change the argument to a reference. Currently, only_unique leaves the parameter unmodified. Even if the vector is passed by reference the duplicates will still be present (just at a different position). This has O(n log n) complexity.
you need to create "set" structure,
it makes it possible to insert values from vector and does not insert the duplicates,
so you can check if the size of the set and the vector match or not.
set<int> st;
for (auto i : nums)
st.insert(i);
return st.size() == nums.size();

Iterator(of a vector or string) minus n (iter - n) for c++

Some detail description for my question:
Create an iterator of vector or string in c++ 11.
Do iterator arithmetic, iterator minus n
Question: Will c++ 11 keep the iterator minus n bigger than begin()? (if n is big enough, will the compiler ensure that the iter - n do not exceed the legal range of iterator?)
According to cppreference, iter - n is effectively the same as:
vector<T>::iterator temp = iter;
while(n--) --temp;
return temp;
Assuming iter was a iterator from a vector named container. If n is larger than distance(container.begin(), iter), then at some point from the last while loop, --temp would be equivalent of:
--container.begin();
And according to cppreference, that line would be undefined behavior.
Since an iterator cannot know any information of the originated container, it does not have a way to detect if it is currently container.begin(), thus it cannot ensure it to be remained in the legal range without manually checking against the range.
It will not, it will simply perform the arithmetic operations and print the values in negative number.
Performed the code using VSCode.
#include<conio.h>
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> v = {1,2,3,4,5,6};
vector<int> :: iterator it;
for(it=v.begin();it!=v.end();it++)
cout<<*it-6<<endl;
return 0;
}
and the results were :
-5
-4
-3
-2
-1
0
No, iterator arithmetic will not do any bounds checking on the result. You can easily end up with an invalid iterator.
A random access iterator such as given by std::vector will allow you to do subtraction, so you can impose your own bounds checking.
it2 = it - min(n, it - container.begin());

for each in C++ fails to update the vector

I for_each an vector and changed the vector inside the for-loop. However, when I ran the program, after the program left the for-loop the vector was still unchanged. What caused the problem? If I still want to use for_each loop, how can I fix it?
Here is the code (my solution for leetcode 78):
class Solution {
public:
void print(vector<int> t){
for(int a:t){
cout<<a<<" ";
}
cout<<endl;
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
res.push_back(vector<int>{});
int m=nums.size();
for(int a:nums){
cout<<"processing "<<a<<endl;
for(auto t:res){
vector<int> temp{a};
temp.insert(temp.end(),t.begin(), t.end());
res.push_back(temp);
cout<<"temp is ";
print(temp);
res.reserve();
}
// int s=res.size();
// for(int i=0;i<s;i++){
// vector<int> temp{a};
// temp.insert(temp.end(), res[i].begin(), res[i].end());
// res.push_back(temp);
// }
}
return res;
}
};
If I used the placed I commented out to replace the for_each loop, it gave the correct solution.
The shown code exhibits undefined behavior.
Inside the for-loop:
res.push_back(temp);
Adding new elements to a std::vector invalidates all existing iterators to the vector (there are several edge cases, on this topic, but they are not relevant here). However, this is inside the for-loop itself:
for(auto t:res){
The for-loop iterates over the vector. Range iteration, internally, uses iterators to iterate over the container. As soon as the first push_back here adds a value to the vector, the next iteration of this for-loop is undefined behavior. Game over.
The problem here is that you are looping over the subsets created so far and then add more subsets in the same loop, appending them. There are two problems with this.
First (as pointed out by Sam), vector::push_back() may invalidate iterators which control the loop, thus breaking the code.
Second, even when using a container (such deque or list), where push_back() would not invalidate any pointers, your loop would run indefinitely, as you keep adding new elements.
The correct way is to only loop the subsets created before the loop starts, but then add new subsets, i.e. doubling the number of subsets. The easiest way to achieve this is to use good old index-based loops and allocate/reserve enough subsets (2^n) at the onset.
vector<vector<int>> subsets(vector<int> const& nums)
{
const auto n=nums.size();
vector<vector<int>> subset(1<<n); // there are 2^n distinct subsets
for(size_t i=0,j=1; i!=n; ++i) // loop distinct nums
for(size_t k=j,s=0; s!=k; ++s) { // loop all subsets so far s=0..j-1
auto sset = subset[s]; // extract copy of subset
sset.push_back(nums[i]); // extend it by nums[i]
subset.at(j++) = move(sset); // store it at j
}
return subset;
}

find function in c++ for a vector

Okay, so I am new to this, and I am having trouble understanding this.
I made this code,
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main (void)
{
vector <int> a;
int i;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);
vector <int>::iterator position = find(a.begin(),a.end(),6);
cout<<*position<<"\n";
return 0;
}
I read everywhere that the find function if it doesnt find anything returns the iterator to the end of the vector. So, when, I do this, and search the value 6 which is not present in the vector, it should return the iterator to the end of the vector which is actually 5. On printing the actual value, it should then print 5 but it prints 0. Why is it that if it returns the iterator to the last value if find doesnt find anything in the vector relating to the value, then it prints 0?
No, it will not return the end of the vector it will return vector.end()
The former implies the last element of the vector, which would be 5.
The latter, vector.end(), is past the end of the vector
This adds slight confusion because vector.begin() does indeed point to the first element of the vector, but this is necessary due to the way you can iterate these containers.
Why is it that if it returns the iterator to the last value if find doesnt find anything in the vector relating to the value, then it prints 0
0 is a garbage value that you get when you dereference the end iterator of the vector. This is undefined behavior, so you could potentially get any number at all. A proper code looks like this:
vector <int>::iterator position = find(a.begin(),a.end(),6);
if (position != a.end()) {
cout<<*position<<"\n";
} else {
cout << "not found" << endl;
}
Once you get the result, you need to compare it to a.end() to see if the result is valid. If the result is not valid, you may not dereference the iterator to avoid undefined behavior.
As you can see in the documentation for vector::end(), the end() iterator is not the same as the last element in the vector. Rather, it is past the last element. Accessing that element results in undefined behavior.

Is it possible to efficiently check whether STL std::deque erase succeded?

We are trying to use the std::deque erase member function. The return value of the std::deque erase(iterator) member function is a A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the container end if the operation erased the last element in the sequence.
We were wondering whether it is possible to efficiently check whether STL std::deque erase succeded. Thank you. An excerpt of our code is shown below:
typedef std::multimap<char *,Range>::const_iterator I;
std::pair<I,I> b = mmultimap.equal_range(TmpPrevMapPtr);
for (I i=b.first; i != b.second; ++i){
std::deque<Range>::iterator iter;
std::deque<Range>::iterator it;
iter = std::lower_bound(ranges_type.begin(),ranges_type.end(),i->second);
if (iter != ranges_type.end() && !(i->second < *iter)){
it = ranges_type.erase(iter);
}
}
std::deque::erase always succeeds (unless of course, it gets an invalid iterator, in which case the results are undefined).
Check if the size of dequeue decreases by the number of elements you erased.
With regards to the concern about performance, Time Complexity for dequeue::size is O(1)
#include <iostream>
#include <deque>
using namespace std;
int main ()
{
unsigned int i;
deque<unsigned int> mydeque;
// set some values (from 1 to 10)
for (i=1; i<=10; i++) mydeque.push_back(i);
cout << "\nmydeque contains:"<<mydeque.size();
// erase the 6th element
mydeque.erase (mydeque.begin()+5);
// erase the first 3 elements:
mydeque.erase (mydeque.begin(),mydeque.begin()+3);
//Total Elements erased = 4
cout << "\nNow mydeque contains:"<<mydeque.size();
return 0;
}
If the erase succeeded the deque will be shorter than it was. Alternatively, wrap your code in a function (which you should be doing in any case) and have the function return whether or not an erase happened.