I have two maps. The keys of the two maps are the same. The mapped-value of the second one is a pointer, which points to the mapped-value of the first one. When I erase the element in the first map, the pointer in the second map does not vanish automatically. I should first erase the second map and then erase the first one.
// two maps
map<int, int> a;
map<int, int*> pt_a;
int N = 5;
for (size_t i = 0; i < N; i++)
{
a.insert({ i,2 * i });
pt_a.insert({ i,&(a[i]) });
}
// erase the first element of a
a.erase(a.begin());
// after erase
for (auto& i : a) cout << i.first << " " << &(i.second) << endl;
cout << endl;
for (auto& i : pt_a) cout << i.first << " " << i.second << endl;
Is there anything in C++ can simplify this code? If the element in the first map is erased, the corresponding one in the second map is also erased automatically.
If I erase the element in the second map, the memory of pointer is free or not? Should I use std::share_ptr in this case?
Thanks!
Related
I do not know, why does it output 1024?
vector<int> default_container = { 1,2,3,4,5,6,7,78,8,1024 };
cout << *default_container.end() << endl; // 0
default_container.pop_back();
for (auto it : default_container)
{
cout << it << ",";
}
cout << endl;
cout << *default_container.end() << endl; // 1024 why?why?why?why?
cout << *--default_container.end() << endl; // 8
Your program has Undefined behavior!
You are de-referencing the end iterator, at the lines
cout << *default_container.end() << endl;
...
cout << *default_container.end() << endl;
which gives you undefined behavior. Form cppreference.com the std::vector::end, std::vector::cend
Returns an iterator to the element following the last element of the vector.
This element acts as a placeholder; attempting to access it results in undefined behavior.
Means, anything can be happened; therefore you shouldn't be relaying on its result and should not be doing it!
That being said, it looks like that you want to access the last element in the vector. If that the case, for a non-empty vector you have multiple other (safe) choices:
Using std::vector::back
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << default_container.back();
Using std::prev
#include <iterator>
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << *std::prev(default_container.end());
Using reverse iterator std::rbegin
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << *std::rbegin(default_container);
As a side note, see: Why is "using namespace std;" considered bad practice?
The previous answer says it all.
In other words you're not supposed to use end() for anything else then comparing an iterator to.
Eg.
for (auto it = container.begin(); it < container.end(); ++it)
Also note that your line for (auto it : default_container)
isn't creating an iterator but literally an int.
// foreach value in container
for(int value : default_container)
{
cout << value;
}
note that if you're not planning to change the values you're iterating over you can use this :
for(const auto value : default_container) {}
or if your containter contains objects (instance of classes)
for(const auto& object : container) {}
Take the following simple program:
struct Foo
{
int x;
int y;
int z;
string s;
};
int main()
{
Foo f1 = { 42,21,11, "Hello world" };
std::map<int, Foo> foomap;
foomap[400] = f1;
Foo* ptr = &foomap[400]; // cache a pointer to the element we just inserted.
cout << ptr->x << " " << ptr->y << " " << ptr->z << " " << ptr->s << std::endl;
// fill the map up with a bunch of other random items at random indices
for (int x = 0; x < 10000; x++)
{
int i = rand();
Foo f = { rand(), rand(), rand(), "Another string" };
if (foomap.find(i) == foomap.end())
{
foomap[i] = f;
}
}
Foo* ptr2 = &foomap[400];
cout << "f1 insert location has " << ((ptr == ptr2) ? "not changed" : "changed") << std::endl;
cout << ptr->x << " " << ptr->y << " " << ptr->z << " " << ptr->s << std::endl;
return 0;
}
So the program above caches a pointer to an item in the map. Then adds a whole lot more items into the map, and then validates if the first inserted item has changed location.
I was somewhat surprised when I ran it. The cached pointer stays intact:
42 21 11 Hello world
f1 insert location has not changed
42 21 11 Hello world
I would have assumed that as the map grows with respect to the number of items in it, the implementation might move items around - just like std::vector absolutely does.
So my question is this: Are items inserted into a map guaranteed to be at the same address as long as it's not removed from the map or replaced? Or is this implementation specific?
Yes, insertion / emplacement operations on map never invalidate iterators or references to existing items.
26.2.6 Associative containers [associative.reqmts]
9 The insert and emplace members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.
I need to find the range of the first elements of a vector pair. I need this range for a map, which counts the duplicate entries in this vector.
Here is a code snipped and how I managed it. Maybe there is another, better solution?
unordered_map<int, int> frequency;
vector<pair<unsigned int,Point>> Roi_Num_Koord;
vector<int> Roi_first_Element;
int main()
{
// Part1: fill the Vector pair
Roi_Num_Koord.emplace_back(make_pair(0,Point(3.6));
Roi_Num_Koord.emplace_back(make_pair(1,Point(4,8));
Roi_Num_Koord.emplace_back(make_pair(2,Point(8.3));
Roi_Num_Koord.emplace_back(make_pair(3,Point(4,6));
// Part 2: now copy the first element to another vector
for (int i = 0; i < Roi_Num_Koord.size(); i++)
{
Roi_first_Element.emplace_back(Roi_Num_Koord[i].first);
}
// Part 3: now do the duplicate search (Code was taken out of the internet)
for (int i : Roi_first_Element)
{
++frequency[i];
cout << "freque "<<frequency[i] << endl;
}
for (const auto& e : frequency)
{
if (e.second == 5)
{
std::cout << "Roi " << e.first << " encountered " << e.second << " times\n";
}
}
}
So is there a possibility to remove Part 2 and find out the range of the first Element of Roi_Num_Koord?, so that I don't have to copy the first elements of this vector to the other vector (Roi_first_Element)
Yes the second step is completely redundant. You just iterate through the container and whenever you need first element of the pair you say it explicitly pretty much like you do in Step 2.
for(const pair<unsigned int,Point>& element : Roi_Num_Koord)
{
++frequency[element.first];
cout << "freque " << frequency[element.first] << endl;
}
I'm trying to print elements of a vector of list pair in a hash-table program in C++.
If I use the C++11 auto it's working but if i use a iterator
for (vector<int>::iterator i = arr_Hash[i].begin(); i != arr_Hash[i].end(); ++i)
//for (auto index = arr_Hash[i].begin(); index != arr_Hash[i].end(); index++)
{
cout << i->second;
cout << " ";
}
Error list: https://i.imgur.com/rDejBGG.png
How can I use the iterator here?
vector<int>::iterator i = arr_Hash[i].begin()
You're reusing the variable i here. Call it something else.
std::cout << i->second;
i is a std::vector<int>::iterator. Dereferencing it gives you an int&, which has no second member. You probably just want std::cout << *i;
The iterator for arr_Hash[i] needs to be on the same type as the vector.
Namely, if the type of arr_Hash[i] is vector<pair<int,int>> then it's iterator needs to be vector<pair<int,int>>::iterator.
Howerver, you should Prefer a range-for-statement to a for-statement when there is a choice.
for (auto& e : arr_Hash[i])
cout << i->second << " ";
My understanding is the iterators of associative containers are not invalidated during insert or erase (unless the node pointed by iterator is erased). But in the below program
the insert seems to invalidate the iterator. Is my understanding wrong?
typedef std::set<unsigned int> myset_t;
int main(int argc, char **argv)
{
myset_t rs;
myset_t::reverse_iterator rit;
myset_t::reverse_iterator srit;
int ii = 500;
rs.insert(10);
rs.insert(11);
rs.insert(12);
rs.insert(13);
rs.insert(14);
rs.insert(100000);
rs.insert(102000);
rs.insert(103000);
rit = rs.rbegin();
while(rit != rs.rend()) {
srit = rit;
if (*rit < 100000) {
cout << "bailing here " << *rit << endl;
return 0;
}
rit++;
cout << "Before erase " << *rit << endl;
rs.erase(*srit);
cout << "Before insert " << *rit << endl;
rs.insert(ii);
cout << "After insert " << *rit << endl;
ii++;
}
cout << "Out of loop" << endl;
}
===
The output is
Before erase 102000
Before insert 102000
After insert 14
bailing here 14
=====
The promised behavior for iterators of a standard container does not hold for reverse iterators of that container.
A reverse iterator actually stores, as a member, the normal (forward moving) iterator which comes after the element to which the reverse iterator refers when dereferenced. Then when you dereference the reverse iterator, essentially it decrements a copy of this stored normal iterator and dereferences that. So this is a problem:
rit = rs.rbegin(); // rit stores rs.end()
srit = rit; // srit also stores rs.end()
rit++; // rit stores a normal iterator pointing to the last element
rs.erase(*srit); // this deletes the last element, invalidating the normal
// iterator which is stored in rit. Funnily enough, the
// one stored in srit remains valid, but now *srit is a
// different value
Reverse iterators behave this way because there is no "before begin" iterator. If they stored the iterator to the element to which they actually refer, what would rs.rend() store? I'm sure there are ways around this, but I guess they required compromises which the standards committee was not willing to make. Or perhaps they never considered this problem, or didn't consider it significant enough.