Hello guys I have a list iterator type which I want to convert to UINT.
std::set<UINT> volSet;
UINT ssidBase = 1;
UINT ssidEnd = 2;
volSet.insert( ssidBase );
volSet.insert (ssidEnd);
UINT ssidStart = evf::volSet.begin();
I want the first value in the volSet to be set to ssidStart. I'm getting an error when I run this?
cannot convert 'std::_Tree<std::_Tset_traits<unsigned int, std::less< unsigned int>, std::allocator< unsigned int>, false> >::iterator' to 'UINT' in initialization
Any help is appreciated?
As such, iterators in C++ are basically pointers.
So the general idea is that you need to dereference that iterator to access the actual value it points to, like so:
UINT number = *(container.begin());
It is not clear exactly what the intention is with inserting a one and then a two. Granted many more unsigned values can be inserted later. However, by inserting a one, the only other possible value that will be lower is zero. The insert method for the STL set, map, unordered_set, and unordered_map containers (now called Standard Library) returns a pair.
Insert method reference links:
set
http://www.cplusplus.com/reference/set/set/insert/
map
http://www.cplusplus.com/reference/map/map/insert/
unordered_set
http://www.cplusplus.com/reference/unordered_set/unordered_set/insert/
unordered_map
http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/
If the element already exists in a set, the first pair element is the iterator pointing to the existing element with the second element set to false. With a successful insert (e.g. the key is not already present in the set), the first element of the pair points to the element that has been successfully added, with the second pair element set to true.
Using a set to guarantee the first (lowest) element (e.g. where the begin() method will always return an iterator pointing to unless the set is empty), does guarantee that the lowest value in the set is always found in constant time (e.g. O(1); big Oh of one).
A coding example with some values in C++11.
std::set<UINT> volSet;
pair <std::set<UINT>::itertor, bool> p;
//
// Using the same notation on unsigned int for consistency,
// insert 500 unsigned values into the volSet container.
//
for (UINT i = 500; i >= 0; i--)
{
p = volSet.insert(i);
if (p.second == false)
{
cerr << "volSet insertion warning!! The value for volSet already has: ";
cerr << i << endl;
}
}
//
// Do business logic, deletions/insertions from/to the volSet, and so on...
//
// Now obtain the lowest value inside the volSet and set it to a local variable.
// It is assumed that evf is a user defined namespace.
//
std::set<UINT>::iterator ii = evf::volSet.begin();
UINT ssidStart = *ii;
//
// Alternatively, implement without declaring a local iterator as Victor
// has shown above. Note that the parenthesis here are important. The call
// to begin() has to occur prior to the dereference operator call.
// Note that the sample above intentionally sets the ii iterator
// before dereferencing.
//
UNIT lowValue = *(evf::volSet.begin());
I hope this is helpful to understand the difference between iterators and container elements.
Related
I am trying to do dfs over a graph defined as unordered_map<string,set<pair<string,int>>> g;
So here is my dfs code:
void dfs(string u){
for(auto v=g[u].begin();v!=g[u].end();v++){
if(!v->second){
cout<<v->first<<endl;
res.push_back(v->first);
v->second = 1;
dfs(v->first);
}
}
}
I am trying to change the value of v->second to 1, but I am getting an error of
cannot assign to return value because function 'operator->' returns a const value
v->second = 1;
So is there any other way to change the second value of the pair?
You cannot modify value of an element of std::set as it would break it's invariant. What you can do though is to remove existing element and insert modified one. But as you iterate over the set then such modification inside loop would be overcomplicated. So I suggest you remove all elements that satisfy your condition and then insert them all back modified.
Though it is not clear why you need int value of std::pair to be a part of the key. If that is a mistake, then just use std::unordered_map<string,std::map<string,int>> insted and then you can modify v->second without any problem (but that value would not be a part of the key anymore).
Note your loop is written quite ineffective way - you are invoking std::unordered_map::operator[] on every iteration. Instead you better get a reference to that element and use it:
void dfs(string u){
auto &gu = g[u];
for(auto v=gu.begin();v!=gu.end();v++){
...
The problem comes from begin() method of set. As stated in cpp ref:
Because both iterator and const_iterator are constant iterators (and may in fact be the same type), it is not possible to mutate the elements of the container through an iterator returned by any of these member functions.
This means the v is in fact const, so operator->() will be const version too. So you will not be able to change second.
BTW, a suggestion: use bool for visiting not int. it helps readability.
I came across this c++ code for counting frequency in a vector.
std::map<std::string, int> countMap;
// Iterate over the vector and store the frequency of each element in map
for (auto & elem : vecOfStrings)
{
auto result = countMap.insert(std::pair<std::string, int>(elem, 1));
if (result.second == false)
result.first->second++;
}
from https://thispointer.com/c-how-to-find-duplicates-in-a-vector/. I want to ask what does
result.second == false mean?
Since std::map and the other non-multi associative containers only store unique items there is a chance that when you insert something into it it wont actually insert since it may already be present. insert therefore returns a std::pair<iterator, bool> where the bool will be true if the insert succeeded and false otherwise.
I would like to point out you can get rid of the if statement in the loop. Because of how operator[] of a map works the loop can be replaced with
for (const auto & elem : vecOfStrings) // also added const here since we don't need to modify elem
{
++countMap[elem];
}
And now if elem exists then you increment the value and if it doesn't you added elem to the map and increment its value.
std::map::insert returns a std::pair<iterator, bool>.
pair.first is an iterator to the newly inserted element OR the element that was already in the map and prevented the insertion.
pair.second tells whether or not the insertion happened.
result.second == false is detecting the case where nothing was inserted into the map due to a key collision.
Note that with C++17, this can be written to be a bit more clear:
auto [itr, inserted] = countMap.insert({elem, 1});
if (!inserted) {
itr->second++;
}
From cppreference:
Returns a pair consisting of an iterator to the inserted element (or
to the element that prevented the insertion) and a bool denoting
whether the insertion took place.
result.first gives you the iterator to the element, while result.second tells you whether the element was actually inserted or did already exist.
std::map::insert returns a pair where the second value indicates whether any insertion actually happened. If the value is false, this means no value was inserted into the map because a value with the same key already exists.
However, the code shouldn’t be written like this: comparing against boolean literals is a nonsensical operation. Instead you’d write
if (not result.second)
// or
if (! result.second)
std::map::insert returns a pair of iterator and a bool. The bool indicates whether the insertion actually took place. The code you listed seems to increment the mapped int if key collision happens on insert.
I know that, if I insert a value into a std::map I can obtain an iterator referring to the inserted element (or the element which was previously there) by checking inserts return value like so:
std::map<int, char> m;
auto ret = m.insert(std::make_pair(1, 'A'));
if (ret.second)
std::cout << "it worked" << std::endl;
// ... now iterations over the map starting at ret.first
However, I was wondering whether it is legal to manipulate the obtained iterator afterwards, e.g. assign the desired value in the case of a failure.
std::map<int, char> m;
auto ret = m.insert(std::make_pair(1, 'A'));
if (!ret.second)
ret.first->second = 'A'; // assign the value in case it went wrong
I noticed that this seems to work, but I am not sure whether this is the desired behaviour since everything I found in case of an failed insertion was to use the operator[] instead. However this would not be a solution for me, because I need the iterator returned by insert afterwards and I can't use insert and the operator[] because of performance reasons.
Long story short: Is it valid to manipulate the data referenced by an iterator returned from std::maps insert()?
Long story short: Is is valid to manipulate the data referenced by an iterator returned from std::maps insert()?
Yes, this is just fine. You cannot modify the key as that is const but you can modify the value the key is mapped to as much as you want.
Say that I have the following example using a set in c++:
set <int> a;
for (int i = 0; i <10; i++){
//Assume i is a random number
a.insert(i);
}
How can you find the maximum and minimum values for the set example shown above? Ideally I thought that the following would work but it gives the following error:
error: cannot convert 'std::_Rb_tree_const_iterator<int>' to 'int' in assignment
I'm using the following functions to try getting max/min:
min = a.begin();
max = a.end();
First of all, begin and end return iterators, which you need to perform indirection on (*) to get the element they point at.
Secondly, end returns the past-the-end iterator, so doesn't actually refer to the last element. You can instead use the reverse begin iterator.
min = *a.begin();
max = *a.rbegin();
a.begin() and a.end() are iterators, not elements. Use
min = *a.begin();
to receive min element and
max = *a.rbegin();
to receive max.
max = *a.end();
will not work because it points on the next element after the last one. So it will return garbage.
As others have said, an iterator (as the one returned by begin() or rbegin()) must be dereferenced to retrieve the value it points to.
But, before dereferencing, the iterator must be checked for validity. For example, on an empty vector begin() will return an out-of-range iterator (pointing one position past the last).
So, a more cautious way would be:
// assuming a is a vector<int>
vector<int>::const_iterator p = a.cbegin(); // or use auto to hide iterator type
int min_val = p != a.cend()? (*p) : (INT_MAX); // if empty, yield a special value like INT_MAX
let's say I have a map whose key is a pair and whose custom comparator guarantees unicity against the first element of that pair.
class comparator
{
public:
bool operator()(const std::pair<std::string, std::int>& left,
const std::pair<std::string, std::int>& right)
{
return left.first < right.first;
}
};
std::map<std::pair<std::string, std::int>, foo, comparator>;
Now I'd like this map to be more intelligent than that, if possible.
Instead of being rejected at insertion time in case a key with the same string as first element of the pair already exists, I'd to overwrite the "already existing element" if the pair's integer (.second) of the "possibly going to be inserted element" is bigger.
Of course I can do this by looking in to the map for the key, getting the key details and overwriting it if necessary.
Alternatively I could adopt a post-insertion approach with a multimap on top of which I would iterate to clean up duplicates keeping just the key with the biggest pair integer.
The question is : can I do that natively by overriding part of the stl implementation ([] operator - insert method) or improving my custom comparator and then simply relying on map's insert method ?
I don't know if this is accepted but we could imagine having a non const comprator which would be able of updating the already stored (key, value) pair under certain circumstances.
ValueThe answer to your question is that you cannot do it.
There are two problems with your proposed implementation:
The keys must remain const as they are the index for the map
Independent of what the comparator did to the elements it is comparing the std::map would still insert the item before or after left based on the return of the comparator
The solution to the problem is as suggested by #MvG. Your key should not be paired, it is your value that should be paired.
This has the added benefit that you don't need a custom comparator.
The problem is that you will need a custom inserter:
std::pair< int, foo >& tempValue = _myMap[ keyToInsert ];
if( valueToInsert.first >= tempValue.first )
{
tempValue = valueToInsert;
}
Note that this will only work if all the valueToInsert.firsts that you use are positive, cause the default constructor for an int is 0. If you had negative valueToInsert.firsts the default constructed value pair would be inserted instead of your element.