C++ primer 5ed equal_range for associative containers - c++

In C++ prime 5 Ed chapter 11. Associative containers. "Table 11.7. Operations to Find Elements in an Associative Container":
It is said: "c.equal_range(k) returns a pair of iterators denoting the elements with key k. if k is not present, both members are c.end()."
set<int> si{ 5, 7, 23, 16, 81, 24, 10};
auto it = si.equal_range(13);
cout << *it.first << " " << *it.second << endl; // 16 16
But as you can see above 13 was not found but it returns a pair of iterators for elements16, 16?!

Running this program, it works as intended: It returns the end iterators.
int main (int argc, char** argv) {
std::set<int> si{ 5, 7, 23, 16, 81, 24, 10};
auto it = si.equal_range(99);
if(it.first == std::end(si)) {
std::cout << "Element not found." << std::endl;
}
else {
std::cout << *it.first << ", " << *it.second << std::endl;
}
return 0;
}
But, if I were to check for 13, I'd get back 16, 16.
According to cppreference.com
Returns a range containing all elements with the given key in the container. The range is defined by two iterators, one pointing to the first element that is not less than key and another pointing to the first element greater than key. Alternatively, the first iterator may be obtained with lower_bound(), and the second with upper_bound().
16 just happens to be the first element that is not less than and also greater than 13 in your example.

Related

Is a reverse iterator constructed from an iterator is its previous iterator?

On https://en.cppreference.com/w/cpp/iterator/reverse_iterator it is said:
std::reverse_iterator is an iterator adaptor that reverses the direction of a given iterator. In other words, when provided with a bidirectional iterator, std::reverse_iterator produces a new iterator that moves from the end to the beginning of the sequence defined by the underlying bidirectional iterator.
For a reverse iterator r constructed from an iterator i, the relationship &*r == &*(i-1) is always true (as long as r is dereferenceable); thus a reverse iterator constructed from a one-past-the-end iterator dereferences to the last element in a sequence.
So I've tried this code to understand more:
int main() {
std::deque<int> di{ 1, 1, 2, 3, 5, 8, 13 }; // fibonacci series
// deque has bi-directional iterators
std::deque<int>::iterator offEnd = di.end(); // one-past the last element in di
std::deque<int>::reverse_iterator r(offEnd); // constructing a reverse iterator from an iterator from deque<int> di
std::cout << &offEnd << " : " /*<< *r */ << std::endl;
std::cout << &(offEnd - 1) << " : " << *(offEnd - 1) << std::endl;
std::cout << &*r << " : " << *r << std::endl;
}
The output:
0023FDAC :
0023FC9C : 13
0048C608 : 13
Why the iterators have the same value but on different addresses???!!!
Does this mean &*r == &*(i-1) is not correct?
The address are different because you have different objects. (offEnd - 1) and r are distinct objects. Since they are, they have different addresses. What you need to do is dereference the iterator, and then get that address. Doing that gives you
int main()
{
std::deque<int> di{ 1, 1, 2, 3, 5, 8, 13 }; // fibonacci series
// deque has bi-directional iterators
std::deque<int>::iterator offEnd = di.end(); // one-past the last element in di
std::deque<int>::reverse_iterator r(offEnd); // constructing a reverse iterator from an iterator from deque<int> di
std::cout << &(*offEnd) << " : " /*<< *r */ << std::endl;
std::cout << &(*(offEnd - 1)) << " : " << *(offEnd - 1) << std::endl;
std::cout << &*r << " : " << *r << std::endl;
}
which outputs:
0xed3c8c :
0xed3c88 : 13
0xed3c88 : 13
And as you can see the addresses are the same since the iterators point to the same element.
Do note that
&(*offEnd)
is illegal and is undefined behavior. There is no object at end() so it is illegal to dereference the past the end iterator.
The reason is clear as you can see also when you are querying the address of offEnd and offEnd-1, which are the same. You are querying the address of the iterator and this stays the same if you move within this iterator with the --operator.

Does std::vector::assign/std::vector::operator=(const&) guarantee to reuse the buffer in `this`?

If I assign or copy one vector to another (that has the same or bigger capacity than the size of the former), can I assume that the buffer of the latter will be reused?
The following example demonstrates that I can, however, is it guaranteed by the standard?
Is there any difference between behaviour of std::vector::assign and std::vector::operator= in this regard?
#include <vector>
#include <iostream>
#include <cassert>
int main()
{
std::vector a {1, 2, 3, 4, 5};
std::vector b {1, 2, 3, 4};
std::vector c {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "1 ==== " << a.capacity() << " " << a.data() << std::endl;
const auto* pa = a.data();
a = b;
assert(pa == a.data());
std::cout << "2 ==== " << a.capacity() << " " << a.data() << std::endl;
a = c;
assert(pa != a.data());
std::cout << "3 ==== " << a.capacity() << " " << a.data() << std::endl;
}
Live example.
Update: This answer mentions that
void assign(size_type n, const T& t);
is equivalent to
erase(begin(), end());
insert(begin(), n, t);
Does the standard really formulate it this way and does it apply to all overloads of std::vector::assign?
Short answer
No.
Not so short answer
The standard does not manually define these operations on vector. It only defines them as a requirement for containers. [vector] says
A vector satisfies all of the requirements of a container and of a reversible container (given in two tables in [container.requirements]), of a sequence container, including most of the optional sequence container requirements ([sequence.reqmts]), of an allocator-aware container (Table 67), and, for an element type other than bool, of a contiguous container. The exceptions are the push_­front, pop_­front, and emplace_­front member functions, which are not provided. Descriptions are provided here only for operations on vector that are not described in one of these tables or for operations where there is additional semantic information.
The only places where these operation are mentioned are Container requirements and Sequence container requirements. Nothing supports your assumption.

Lower bound error

I am following this tutorial on Lower_bound() in C++. I have made a simple code to find a number in a vector lesser than or equal to a number from the vector + any number that I want. My code goes like this
cout << *lower_bound(A.begin(), A.end(), A[x] + 3);
where the vector A[] is sorted. But the code points it to a number greater than the sum of both the numbers.
For example if my vector has values as 0, 3, 5, 8, 12 and I want it to print the nearest number lesser than or equal to A[3] + 3 = 11 it should give output as 8 but it gives the output of 12. Any reasons?
Here is my code:
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> A = {0, 5, 3, 12, 8};
sort(A.begin(), A.end());
cout << "A[3] = " << A[3] << endl;
cout << *lower_bound(A.begin(), A.end(), A[3] + 3) << endl;
return 0;
}
lower_bound
Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val.
In your case it is not returning the last value less than 11. It returns the first value not less than 11, which in your example is 12.
If you want the largest number not greater than your target, you can use std::greater<> and reverse iterators (or sort by std::greater<>)
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> A = {0, 5, 3, 12, 8};
std::sort(A.begin(), A.end());
std::cout << "A[3] = " << A[3] << std::endl;
std::cout << *std::lower_bound(A.rbegin(), A.rend(), A[3] + 3, std::greater<int>{}) << std::endl;
return 0;
}

Randomly select an element from an enumeration in a type-safe way with newest C++

Is there a way to randomly select an element from an enumeration in a type-safe way?
The best way to do it, that I could find, is to introduce a terminator value as the last element of the enum, so you know how many values there are, then generate a random integer in the appropriate range that you cast to the enum. But a terminator value does not represent anything, so then you have an invalid enum value, and this is not type-safe. Is there a better way to do it in the latest C++ standards?
This seems like a good use case for a std::map
std::map<std::string, const int> nicer_enum {{"Do", 3}, {"Re", 6}, {"Mi", 9}};
std::cout << nicer_enum["Re"] << '\n'; // 6
auto elem = nicer_enum.cbegin();
std::srand(std::time(nullptr));
std::advance(elem, std::rand() % nicer_enum.size());
std::cout << elem->second << '\n'; // 3, 6 or 9
for (const auto &kv : nicer_enum)
std::cout << kv.first << ": " << kv.second << ' '; // Do: 3 Mi: 9 Re: 6
std::cout << '\n';

Individual elements in a std::vector [C++]

What's the best way to select individual elements from a C++ std::vector?
I'm used to C-style arrays and this is the first time I'm using vectors.
I'm looking for something like:
std::vector<std::string> myvector;
astring = myvector[1];
bstring = myvector[3];
cstring = myvector[10];
And so on.
There are several ways to access elements in a std::vector:
myVector[3] - access the 4th element (0-indexed).
myVector.at(3) - access the 4th element with bounds checking. Throws an exception if the index is not less than the number of elements.
iterating over all elements with the standard algorithms: std::find(std::begin(myVector), std::end(myVector), 10).
Personally I've never found a use for at(), since I keep track of the index that I'm using anyway. I rarely just take a number from somewhere and stick it into [].
But be aware that accessing an index not less than the number of elements using [] is Undefined Behaviour (if the vector has 4 elements, you access them with 0, 1, 2, and 3). You are expected to be sure it is safe yourself. So in your example, this would be illegal, since you don't put anything into the vector first.
You ask for the best way... The answer is: There is no general best way
The best way is not always the same. It really depends on what your code is doing.
The best way also depends on what you want to achieve, e.g. best performance, best code maintainability, best code readability and so on.
The best way is also based on a personal view.
So just to repeat the answer: There is no general best way
Other answers mentions a number of different posibilities. I'll add one more.
// To iterate over all elements in a vector you can do
for (auto& e : someVector)
{
// Do something with e, e.g. print it
cout << e;
}
There are three general ways to access elements of a vector.
The first one is similar to accessing elements of an array using the subscript operator [].
For example
std::vector<std::string> v = { "Hello", "World" };
std::cout << v[0] << ' ' << v[1] << std::endl;
The second one is to use iterators similar to using pointers. For example
std::vector<std::string> v = { "Hello", "World" };
auto it = v.begin();
std::cout << *it << ' ' << *( it + 1 ) << std::endl;
The third one is to use member function at that checks the boundaries of a vector and throws an exception when an attempt is made to access memory beyond the vector
std::vector<std::string> v = { "Hello", "World" };
std::cout << v.at( 0 ) << ' ' << v.at( 1 ) << std::endl;
Also there are methods to acess the first and the last elements of a vector
for example
std::vector<std::string> v = { "Hello", "World" };
std::cout << v.front() << ' ' << v.back() << std::endl;
To access sequentially all elements of a vector you can use three kinds of loops.
For example
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
or
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( std::vector<int>::size_type i = 0; i < v.size(); i++ ) std::cout << v[i] << ' ';
std::cout << std::endl;
or
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( auto it = v.begin(); it != v.end(); ++it ) std::cout << *it << ' ';
std::cout << std::endl;
Simple use operator[] as you do with arrays. If you want boundary checking use at().
That is generally how you access vectors, they were made to be similar to arrays using the indexing operator.
However, once you when you declare a vector like you do, without passing any arguments to the constructor the vector is empty, which means that any indexing will be out of bounds and you will have undefined behavior.
If you want to specify an initial size, you could pass an argument to the constructor:
std::vector<std::string> myvector(11); // Creates a vector of 11 elements
If you never will change the size of the vector, if the size is fixed at the time of compilation using a compile-time constant, then you should probably be suing std::array instead:
std::array<std::string, 11> myarray;
You can access (i.e. select some element) a std::vector similar to C-style arrays i.e. by using indexes. Similar to arrays, no bound checking is performed in case of std::vector as well when you access some element which is not present. For example, you have inserted 10 elements in vector v but accessing 200th element using v[200] - but it could result undefined behavior, so be careful.