C++ map do plus plus without initialization - c++

map<int, int> mp;
I can understand following code:
mp[1] = 1;
mp[2] = 2;
But how does this make sense?
mp[3]++;
without setting mp[3] = n; (n could be an integer).

When map's operator[] references an element that does not yet exist, it adds the element by value-initializing the entry. For int, value-initializing means initializing to zero. So mp[3]++, if the key 3 did not already exist, ends up setting the associated value to 1.

Please refer the document that managed by SGI: MAP
The mp[3]++ will automatically call mp[3] and if you see the document, you can see when mp[X] is equal to (*((m.insert(value_type(k, data_type()))).first)).second. That means data_type() is calling int().
In short, int() will be called as initial value. and int() is 0; Please refer the following code.
#include <iostream>
using namespace std;
int
main(int,char**)
{
cout << int() << endl;
return 0;
}
PS. I found the right answer and reposted it. Thanks to HisBlog

Related

Using lower_bound() with a set of objects in C++

I'm using a set of objects in C++ to get log(n) times for inserting and finding.
In the code below I'm able to insert elements and make them ordered by x attribute, however, I'm not able to use lower_bound to find the lower bounds based on the same attribute. I don't know how to fix that. Any help will be appreciated.
Most of the examples on sets that I could find were not about a set of objects
struct MyObject {
float x = 0;
float y = 0;
const bool operator < ( const MyObject &r ) const{
return ( x< r.x);
}
};
set<MyObject> nset;
int main(){
MyObject n1;
n1.x=5;
n1.y=1;
MyObject n2;
n2.x=3;
n2.y=2;
nset.insert(n1);
nset.insert(n2);
// this works, the elementes are sorted according to x
for(auto elem: nset){
cout << elem.x << endl;
}
// this doesn't work
set<MyObject>::iterator it = lower_bound(nset.begin(), nset.end(), 1.2);
cout << it->x << endl;
//neither this one
// set<MyObject>::iterator it = nset.lower_bound(1.2);
// cout << it->x << endl;
cout << "hello" << endl;
return 0;
}
I want the lower bound function to point me to the lower bound "x" in the set of objects but the code fails to compile. Compiler error to the first lower bound says: Invalid operands to binary expression ('const MyObject' and 'double')
Compiler error to the second lower bound says: No matching member function for call to 'lower_bound'
EDIT: while the answer provided by user: 1201ProgramAlarm was quite helpful for me to understand and fix the error. I still think it is more convenient in my case to have a lower_bound function that accepts floats rather than objects. So I have implemented the following function to help me achieve that. Copied below just in case others were interested:
set<MyObject>::iterator mylower_bound(set<MyObject> &myset, float val){
MyObject f;
f.x = val;
set<MyObject>::iterator it = myset.lower_bound(f);
return it;
}
nset stores MyObject objects, and lower_bound needs one of the thing stored in the set. You're passing it 1.2, which is a double, but there is no way to construct a MyObject from a double. Thus the compilation failure.
You'll need to pass a MyObject to nset.lower_bound to do your search.

Retrieval of value back from C++ map<T, const T&> returns same object

I created a map of type map<T, const T&>. For current example purpose, let say T is:
class Bar {
public:
Bar(int x) {this->x = x;}
int x;
};
Next I create a map and insert Bar keyed with some integers.
Bar bs[] = {Bar(1), Bar(2), Bar(3)};
map<int, const Bar&> my_map;
for (int i = 0; i < 3; i++) {
const Bar &b = bs[i];
cout << "Setting map." << i
<< " with x = " << b.x << endl ;
my_map.insert(std::make_pair(i, b));
}
So far everything looks good, and b.x prints the values 1; 2; 3 as expected. Next we retrieve these values back.
for (int i = 0; i < 3; i++) {
auto iter = my_map.find(i);
if (iter == my_map.end()) {
cout << "Not found!" << endl;
continue;
}
cout << "map." << i << " = " << iter->second.x << endl;
}
The output prints the last value each time as shown below.
// map.0 = 3
// map.1 = 3
// map.2 = 3
And that's what is confusing to me, as I expect 1; 2; 3. If I replace value type of map with just const Bar it gives 1; 2; 3. I've been trying to make sense out of it, but so far it just looks like undefined behaviour to me. The wildest explanation I can imagine is that &b is like a box storing pointer to the object, and the box ends up being shared across loop, and make_pair uses &b as a box value than like a pointer/reference (and hence explains the last value being printed).
Edit: I understand it may not be good idea to use map like this, but I'm curious why this is happening than what should I be using instead. As in semantically, what did I miss when I wrote this and why it went through compiler, or why compiler made whatever assumption it made.
Edit: Example on repl.it running the code: https://repl.it/repls/IgnorantExhaustedBluejay
Essentially the same problem as here: How can I have a pair with reference inside vector?
Your call to std::make_pair creates a temporary std::pair object that does not have a reference as its second member. The second member of the pair is a regular value of type Bar. Meanwhile, your map stores references. The reference gets bound to the second member of the temporary created by std::make_pair. Later the temporary gets destroyed. The reference becomes dangling.
Each temporary on each iteration of the cycle is apparently created at the same location in memory. So, all these dangling references in your map refer to the same location in memory. Which just happens to hold the residual value of 3 at the time of printing. That explains the output.
A map with raw references is not a very good idea. But if you want to somehow force it to work with raw references, stop using std::make_pair. Instead, manually construct a proper std::pair, making sure to explicitly specify the proper types
my_map.insert(std::pair<const int, const Bar &b>(i, b));
Or you can keep using std::make_pair as follows
my_map.insert(std::make_pair(i, std::cref(b)));
But switching entirely to std::reference_wrapper and std::cref is a better idea.
P.S. BTW, in C++17 mode GCC refuses to compile the code with raw references. C++14 mode does compile it.
I wasn't even aware that it's possible to have a map of references
You should probably simply store the object you want directly :
map<int, Bar> my_map;
If you want the "Bar"s objects to live outside the map, you should use pointers instead of references. Just be sure you don't destruct the Bar objects without removing them from the map :
map<int, Bar*> my_map;
my_map[2] = &bs[0];
and then:
int x = my_map[2]->x;
Edit
I think the map is holding a reference to the temporary pair. You can see this in debug if you extract the creation of the pair :
auto tempPair = std::make_pair(i, b);
my_map.insert(tempPair);
Then after adding bs[0] if we run the creation of the pair, the value of my_map[0] change even before adding the second one:
This makes it work:
my_map.insert(std::make_pair(i, std::reference_wrapper<const Bar>(b)));

C++ vector with std::map?

my function looks like this:
bool getPair(std::vector<std::vector<unsigned short>>Cards) {
std::sort(Cards.begin(), Cards.end(), Cardsort);
std::map<unsigned short, int>Counter;
for (int i = 0; i < 6; i++)
Counter[Cards[i][0]];
for (const auto& val : Counter) {
if (val.second == 2)
return true;
}
return false;
}
I'm pretty sure I'm using std::map incorrectly, I basically have the vector setup like so:
{{2,0},{3,0},{4,1},{3,0},{4,0},{5,0},{6,0}}
where the first number represents value, the second represents card suit. I realize now I should have used an object which may have made this problem less complicated but now I'm trying to use std::map to count how many times the value shows up and if it shows up two times, it show return true (in the vector it would return true at the 3) but I don't think I'm using std::map properly
I want to see if Cards has more than one of the same variable in Cards[i][0], I do not care about duplicates in Cards[i][1]
Tested this and works. Highlighted the fix
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
bool getPair(std::vector<std::vector<unsigned short>>Cards) {
std::sort(Cards.begin(), Cards.end());
std::map<unsigned short, int>Counter;
for (int i = 0; i < 6; i++)
Counter[Cards[i][0]]++; // ++++++++++++++++++ need to alter the value!
for (const auto& val : Counter) {
if (val.second == 2)
return true;
}
return false;
}
int main() {
// your code goes here
// {{2,0},{3,0},{4,1},{3,0},{4,0},{5,0},{6,0}}
std::vector<std::vector<unsigned short>> c = {{2,0},{3,0},{4,1},{3,0},{4,0},{5,0},{6,0}};
std::cout << getPair(c);
return 0;
}
Here´s my suggestion.
Some remarks:
why use two loops? You already have the map entry to check, since you want to increase it, so you can check for doubles aka pairs in the counting loop. No need for a second run. This way it´s much less expensive.
I changed the vector parameter to const&. It´s a very bad idea to pass such a thing by value, at least I can´t see why that could be appropriate in that case
I left out the sorting thingy, can´t see for what end it´s needed, just reinsert it, if necessary. Sorting is very expensive.
you are right in the fact that std:: containers do not need initialization, they are proper initialized, the allocator calls the constructor of new elements, event for e.g. int thats one reason why e.g. int got a default constructor syntax and you can write funny thingies like auto a = int();.
accessing nonexistent keys of a map simply creates them
using a set and counting will definitely not yield better performance
I think the code is pretty easy to read, here you are:
#include <iostream>
#include <vector>
#include <map>
bool getPair(const std::vector<std::vector<unsigned short>>& cards) {
std::map<unsigned short, int> counts;
for(const auto& n : cards) {
if(++counts[n[0]] == 2)
return true;
}
return false;
}
int main()
{
std::vector<std::vector<unsigned short>> cards1 = {{2,0},{3,0},{4,1},{3,0},{4,0},{5,0},{6,0}};
std::vector<std::vector<unsigned short>> cards2 = {{1,0},{2,0},{4,1},{3,0},{5,0},{7,0},{6,0}};
std::cout << getPair(cards1) << "\n";
std::cout << getPair(cards2) << "\n";
return 0;
}
Edit:
Quote of the C++14 Standard regarding access to not existing members of std::map, just for the sake of completeness:
23.4.4.3 map element access [map.access]
T& operator[](const key_type& x);
Effects: If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map.
Requires: key_type shall be CopyInsertable and mapped_type shall be DefaultInsertable into
*this.
Returns: A reference to the mapped_type corresponding to x in *this.
Complexity: Logarithmic.23.4.4.3 map element access
First, you address uninitialized variables in Counter, and then you don't really do anything with it (and why do you run till 6 instead of Cards.size()? Your array has size 7 BTW. Also why there is some kind of sort there? You don't need it.):
std::map<unsigned short, int>Counter;
for (int i = 0; i < 6; i++)
Counter[Cards[i][0]];
They might set the uninitialized variable automatically at 0 or they might not - it depends on the implementation as it is not specified as far as I am aware (in Debug they do set it to 0 but I doubt about the Release version). You'll need to rewrite the code as follows to make it work 100% in all circumstances:
std::map<unsigned short, int> Counter;
for (int i = 0; i < (int)Cards.size(); i++)
{
unsigned short card = Cards[i][0];
auto itr = Counter.find(card);
if(itr == Counter.end())
Counter[card] = 1;
else
itr->second++;
}
I would recommend to use std::set for this task:
std::set<unsigned short> Counter;
for (int i = 0; i < (int)Cards.size(); i++)
{
unsigned short card = Cards[i][0];
if(Counter.count(card)>0)
{
return true;
}
Counter.insert(card);
}
return false;

Can I rely on std::map::operator[] to touch?

I have a C++ program in which I want to insert default values for any keys missing in a std::map. I'm thinking the easiest way to do this would be to use std::map::operator[]() like the POSIX touch command - that is, to leave the value unchanged if it already exists, but to create it if it doesn't. For example,
#include <map>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> keys = {0, 1};
map<int, int> m;
m[1] = 5;
m[2] = 12;
for (const int i : keys)
{
m[i]; // touch value
}
for (auto const & kv : m)
{
cout << kv.first << ", " << kv.second << endl;
}
}
Can I be sure that the compiler won't optimize out the m[i]; statements, since I'm not "doing" anything with them? (Not explicitly assigning to, not reading from.)
Yes you can be sure. Optimizing the call away would change the observable behavior of your program, and the compiler is not allowed to do this (except in the case of RVO).
This is known as the as-if rule.
Yes, you can be sure. It's perhaps more intuitive when you consider that the line in question is equivalent to this:
m.operator[](i);
…and you don't expect arbitrary function calls to be optimised out of your program, if they do anything.
The [] operator does indeed default-construct the value that would be at that key's location if you do not assign it something.
Reference Link
If k does not match the key of any element in the container, the
function inserts a new element with that key and returns a reference
to its mapped value. Notice that this always increases the container
size by one, even if no mapped value is assigned to the element (the
element is constructed using its default constructor).

c++ std::set insert causing segmentation fault

All-
I can't quite figure out why this piece of code is resulting in a segmentation fault... Any help would be great.
#include <iostream>
#include <set>
using namespace std;
class A{
public:
int _x;
A(int x){
_x = x;
}
};
bool fncomp(A a1, A a2){
return a1._x < a2._x;
}
int main(){
bool(*fn_pt)(A,A) = fncomp;
set<A, bool(*)(A,A)> testSet;
for(int i=0; i<10; i++){
cout << i << endl;
A a(i);
testSet.insert(a);
}
}
The output is:
0
1
Segmentation Fault
Well, look at your code. You declared a function fncomp, but are you really using that function anywhere? You initialize fn_pt with it, but fn_pt is not used anywhere. Doesn't it seem strange to you? How do you expect your testSet object to know that you want it to use your fncomp as the comparator, if you never ask your set object to use that function?
You declared your set testSet with an ordinary function pointer type bool(*)(A,A) as a comparator type. That's the type of the comparator. Now, you have to pass the actual value of the comparator to your set object through the constructor parameter
set<A, bool(*)(A,A)> testSet(fn_pt);
or
set<A, bool(*)(A,A)> testSet(fncomp);
(You don't really need that intermediate pointer fn_pt).
You forgot to do that, and the set object used the default constructor argument value for the comparator, which in this case is a null pointer. So, every time your testSet object tries to compare two elements, it performs a function call through a null pointer. No wonder it crashes.
Didn't you get a compiler warning about the unused variable fn_pt?
The variable testSet has an internal comparator of the specified type bool(*)(A,A). Since you didn't initialize it, it was default initialized as NULL. So when testSet tried to insert A(1), it tried to invoke a null function pointer to figure out which order is correct.
You probably meant:
set<A, bool(*)(A,A)> testSet(fn_pt);