why the code cause segmentation fault? - c++11

Below is the code:
vector<set<int>> sets;
set<int> myset{ 3, 5, 8, 2, 10, 9, 7, 15 };
set<int> newSet{ *myset.begin() };
sets.push_back(newSet);
set<int>::iterator it = myset.begin();
it++;
for (; it != myset.end(); it++)
{
for (vector<set<int>>::iterator it1 = sets.begin(); it1 != sets.end(); it1++)
{
set<int> newSet1(*it1); //LINE1
sets.push_back(newSet1); //LINE2
it1->insert(*it); //LINE3
}
}
During the first time entering the second for loop, after LINE2, it1 becomes a NULL, so LINE3 causes segmentation fault. Why after LINE2, it1 is gone?
LINE2 copies newSet1 into the vector sets. Will it copy the whole set or just the address of newSet1?

Let's take a subset of your code:
std::vector<T> sets;
for (auto it = sets.begin(); it != sets.end(); it++)
sets.emplace_back();
The above code exhibits undefined behavior because we modify the vector, and then expect that the iterators to sets are still valid.
In particular, the iterators will become invalid when you perform an insert() and size() == capacity().
About your other question:
LINE2 copies newSet1 into the vector sets. Will it copy the whole set or just the address of newSet1?
It will call the copy constructor of std::set<T> and you will get a copy of the set that you passed as an argument to the push_back() call.

The push_back changes sets, so it1 is no longer reliable. A push_back copies the entire entry into the vector.
Accessing the vector via an index ( e.g., sets[2] ) will work, but bounds are not checked, so be sure the index is within range before accessing.

Related

why the difference between two pointers pointing to different elements of an array is the no of elements between these two pointers?

int main()
{
int arr[]={2,3,5,6,8};
int *ptr;
ptr=&arr[3];
cout<<ptr-arr;
}
Q.why the answer is 3 after compiling the code i.e. as it should be 3*sizeof(int) which in this case should be 3*4=12?
When you subtract pointers you get the distance between them, not the allocated size. The same goes for iterators in STL.
https://en.cppreference.com/w/cpp/language/operator_arithmetic#Additive_operators
The reason is that it is much easier to write correct code.
When the pointer difference between consecutive elements of an array is 1, then you can use ++p to walk through the array (assuming p is a pointer to an element). For example:
int a[10];
for (auto p = a, e = a + 10; p != e; ++p)
*p = 42;
Notice how the code does not have to deal with the size of the elements. If the array type changes from int to double, the code does not have to change and is still correct.

iterate through a set goes to infinite loop

i used exactly the same code in both of my files.
and one is work properly while the other one (this one) goes to endless loop.
int arr[5] = {3, 1, 3, 5, 6};
int main() {
int T = 1;
set<int> s;
for (int tc = 0; tc < T; tc++) {
s.emplace(0);
for (auto x : arr) {
auto end = s.end();
for (auto it = s.begin(); it != end; it++) {
// here's where goes to infinite loop
// and i couldn't figure out why..
s.emplace(*it+x);
}
}
}
return 0;
}
below one is well working one
using namespace std;
int main() {
int arr[5] = {3,1,3,5,6}, sum=20;
set<int> s;
s.emplace(sum);
for (auto x : arr) {
auto end = s.end();
for (auto it = s.begin(); it != end; it++) {
s.emplace(*it-x);
}
}
return 0;
}
expected results are s = {1, 4, 7, 8, ...}
all the sum of all the subset of arr.
but not working properly.. i don't know why..
The issue is that you're inserting elements into the set while iterating over it (with the ranged-for loop). The ranged-for loop semantics do not involve remembering the state of the range before the loop started; it's just like writing:
for(auto it = std::begin(container); it < std::end(container); it++)
Now, std::set is an ordered container. So when you insert/emplace elements smaller than the one your iterator points at, you won't see them later on in the iteration; but if you insert larger elements, you will see them. So you end up iterating only over elements you've inserted, infinitely.
What you should probably be doing is not emplace new elements into s during the iteration, but rather place them in some other container, then finally dump all of that new containers' contents into the set (e.g. with an std::inserter to the set and an std::copy).
(Also, in general, all of your code seems kind of suspect, i.e. I doubt you really want to do any of this stuff in the first place.)

Iterate over first N elements of c++11 std::array

I am using a std::array (c++11). I am choosing to use a std::array because I want the size to be fixed at compile time (as opposed to runtime). Is there anyway I can iterate over the first N elements ONLY. i.e. something like:
std::array<int,6> myArray = {0,0,0,0,0,0};
std::find_if(myArray.begin(), myArray.begin() + 4, [](int x){return (x%2==1);});
This is not the best example because find_if returns an iterator marking the FIRST odd number, but you get the idea (I only want to consider the first N, in this case N=4, elements of my std::array).
Note: There are questions similar to this one, but the answer always involves using a different container (vector or valarray, which is not what I want. As I described early, I want to size of the container to be fixed at compile time).
Thank you in advance!!
From the way you presented your question, I assume that you say "iterate over", but actually mean "operate on with an algorithm".
The behaviour is not specific to a container, but to the iterator type of the container.
std::array::iterator_type satisfies RandomAccessIterator, the same as std::vector and std::deque.
That means that, given
std::array<int,6> myArray = {0,0,0,0,0,0};
and
auto end = myArray.begin() // ...
you can add a number n to it...
auto end = myArray.begin() + 4;
...resulting in an iterator to one element beyond the nth element in the array. As that is the very definition for an end iterator for the sequence,
std::find_if(myArray.begin(), myArray.begin() + 4, ... )
works just fine. A somewhat more intuitive example:
#include <algorithm>
#include <array>
#include <iostream>
#define N 4
int main()
{
std::array<char, 6> myArray = { 'a', 'b', 'c', 'd', 'e', 'f' };
auto end = myArray.begin() + N;
if ( std::find( myArray.begin(), end, 'd' ) != end )
{
std::cout << "Found.\n";
}
return 0;
}
This finds the 4th element in the array, and prints "Found."
Change #define N 4 to #define N 3, and it prints nothing.
Of course, this is assuming that your array has N elements. If you aren't sure, check N <= myArray.size() first and use myArray.end() instead if required.
For completeness:
A BidirectionalIterator (list, set, multiset, map, multimap) only supports ++ and --.
A ForwardIterator (forward_list, unordered_set, unordered_multiset, unordered_map, unordered_multimap) only supports ++.
An InputIterator does not support dereferencing the result of postfix ++.
If you want to iterate over the first N numbers of a std::array, just do something like:
#include <iostream>
#include <array>
int main() {
constexpr const int N = 4;
std::array<int, 6> arr{ 0, 1, 2, 3, 4, 5 };
for (auto it = std::begin(arr); it != std::begin(arr) + N && it != std::end(arr); ++it)
std::cout << *it << std::endl;
}
With C++20, a std::span can be used to create a subset view of a std::array much like std::string_view does for std::string. The span replaces maintaining the variable 'N' for the number of sub-elements.
auto part = std::span(myArray).first(4);
std::find_if(part.begin(), part.end(), [](int x) {return (x % 2 == 1); });
A std::span offers many other benefits. It can be used in range based for loops. And by using std::span.subspan, a span can view any range of elements, not limited to just the first N. A span can also be used not just with std::array, but also with C arrays, std::vector, and other contiguous containers.

how to erase from vector in range-based loop?

I simply wanna erase the specified element in the range-based loop:
vector<int> vec = { 3, 4, 5, 6, 7, 8 };
for (auto & i:vec)
{
if (i>5)
vec.erase(&i);
}
what's wrong?
You can't erase elements by value on a std::vector, and since range-based loop expose directly values your code doesn't make sense (vec.erase(&i)).
The main problem is that a std::vector invalidates its iterators when you erase an element.
So since the range-based loop is basically implemented as
auto begin = vec.begin();
auto end = vec.end()
for (auto it = begin; it != end; ++it) {
..
}
Then erasing a value would invalidate it and break the successive iterations.
If you really want to remove an element while iterating you must take care of updating the iterator correctly:
for (auto it = vec.begin(); it != vec.end(); /* NOTHING */)
{
if ((*it) > 5)
it = vec.erase(it);
else
++it;
}
Removing elements from a vector that you're iterating over is generally a bad idea. In your case you're most likely skipping the 7. A much better way would be using std::remove_if for it:
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](const int& i){ return i > 5; }),
vec.end());
std::remove shift the elements that should be removed to the end of the container and returns an iterator to the first of those elements. You only got to erase those elements up to the end then.
It's quite simple: don't use a range-based loop. These loops are intended as a concise form for sequentially iterating over all the values in a container. If you want something more complicated (such as erasing or generally access to iterators), do it the explicit way:
for (auto it = begin(vec); it != end(vec);) {
if (*it > 5)
it = vec.erase(it);
else
++it;
}
Actually it IS possible, despite what the other answers say.
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
vector<int> ints{1,2,3,4};
for (auto it = ints.begin(); auto& i: ints) { // you can create the iterator here in C++20
if (i == 3)
ints.erase(it--); // Decrement after erasing a single element, and it preserves the iterator
it++;
}
for_each(ints.cbegin(), ints.cend(),
[] (int i) {cout << i << " ";}
);
}
Godbolt
in C++ 23 you can just erase_if(ints, [](const int i){return i==3;});

Find largest element smaller than current with STL

Is there a single one-liner to find the largest element smaller than some element x in a sorted container? I'm essentially interested in any code that will give me an iterator pointing to the largest element smaller than x.
I know how to code this up myself, but would hope that there is a library function for it...
EDIT: Maybe I should make myself clear here, that the version I have in mind that I would code myself is based on binary search and thus runs in O(log n) time. I need to compute this for lists with up to a few million elements.
Since your container is sorted, you can use std::max_element on a range ending with the first element greater than your max, use std::find_if with a lambda, or std::lower_bound to get this range :
int main()
{
std::set<int> s{ 3, 1, -14, 1, 5, 9 };
std::set<int>::iterator result;
int max_value = 6;
result = std::max_element(std::begin(s), std::find_if(std::begin(s), std::end(s), [&](int i) { return i >= max_value; } ) );
std::cout << "max element is: " << *result;
}
Output :
max element is: 5
Live Demo
Or with std::lower_bound :
int main()
{
std::set<int> s{ 3, 1, -14, 1, 5, 9 };
std::set<int>::iterator result;
int max_value = 6;
result = std::max_element(std::begin(s), std::lower_bound(std::begin(s), std::end(s), max_value)) ;
std::cout << "max element is: " << *result;
}
Live Demo
You can just use
lower_bound(container.begin(), container.end(), currentElement);
Now if that is different than container.begin() then there is an element that is smaller than your current one, just substract one and you get it. If you are sure there is always such an element just do
lower_bound(container.begin(), container.end(), currentElement) - 1;
EDIT: Of course I assume that your iterator is bidirectional.
Use prev() in combination with lower_bound()
mycontainer.lower_bound(int_val) returns an iterator to the number that's equal to or greater than int_val
*prev(mycontainer.lower_bound(int_val)) returns the value just before int_val in the container
As a defensive check, first validate that it's not at the beginning of the container:
int result = -1, target = 15;
set<int> _container;
auto _iterator = _container.lower_bound(target);
if(_iterator != _container.begin())
result = *std::prev(_iterator);
Assuming that you have your data in a set s of integers, you can find the largest element smaller than x as follows:
auto it = s.lower_bound( x ); // s.lower_bound has a complexity of O(logn)
if( it == s.begin() )
{
std::cout << "No element found" << "\n";
}
else
{
--it;
std::cout << *it << "\n";
}
lower_bound essentially returns you an iterator it pointing to the smallest element which is >= x. Therefore, it's just previous pointer --it would point to the largest element which is < x. Complexity of this approach is O(log n).

Resources