Reputation: 319
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.
Upvotes: 0
Views: 216
Reputation: 45434
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.
vector::push_back()
may invalidate iterators which control the loop, thus breaking the code.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;
}
Upvotes: 0
Reputation: 118340
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.
Upvotes: 3