110
std::map<int,int> mapy;
++mapy[5];

Is it safe to assume that mapy[5] will always be 1? I mean, will mapy[5] always get the default value of 0 before '++', even if not explicitly declared, as in my code?

2

5 Answers 5

157

As soon as you access the map with the [] operator, if the key doesn't exist it gets added. The int gets "value initialization" invoked - so it will get a value of 0.

Sign up to request clarification or add additional context in comments.

7 Comments

Far as I've experienced, an uninitialized primitive int's initial value is undefined -- that is it can be 0, or it can be -99765521. Ever had an uninitialized int as a class variable and had one of those wacky values appear in your program? That said, I tested this and it seems to work. #include <stdio.h> #include <map> using namespace std; int main() { map<int,int> m ; for( int i = 0 ; i < 100 ; i++ ) m[i]++ ; for( const pair<int,int>& p : m ) printf( "m[%d] => %d\n", p.first, p.second ) ; }
It works in a different way than you think. int x; makes x get an undefined value int x = int(); Again x gets 0 class foo { int x; foo() : x() {} }; foo f; Here f.x will be zero
@bobobobo: See my answer. Initialisation is more complex than that and has multiple "modes of operation" depending on context.
In C++ heap and stack memory are uninitialized - an object get initialized by its default constructor - the language has default constructors for primitive types that initialize them to 0 when you invoke it in the right way See my earlier comment
@JohannesOvermann - corrected
|
69

Yes, it is safe to assume.

The map's operator[] is specified thus:([map.access])

Effects: If there is no key equivalent to x in the map, inserts value_type(std::move(x), T()) into the map.
Returns: A reference to the mapped_type corresponding to x in *this.

T() uses value-initialisation for all T except void ([expr.type.conv]/2), and value-initialisation for a primitive results in zero-initialization ([dcl.init]/7).

Therefore, the expression evaluates to a reference to an object with value zero ([dcl.init]/5).

The operator++ call then increments that object to one, and evaluates to one.

(All references are C++11.)

1 Comment

No idea why your answer was downvoted because you're correct. That's exactly what the specification says (just checked it myself).
12

Rep_Movsd's answer is oversimplified and is likely to lead to numerous extremely dangerous misconceptions. Primitive data-types in C++ do not have initializers. Louis Brandy had a wonderful talk in which he discussed many common C++ errors made at Facebook and a misunderstanding of how std::map<>[] works was one of the errors that he discussed, this is an excellent resource although he doesn't go into detail as to how std::map<>[] actually works.

In general, ints are not initialized and are undefined like all primitive types. That being said when used with std::map<>[] the int has a default value of zero set through a process called value initialization. Value initialization is a process that actually works with structs in general. For instance,

struct Struct {
Struct() : memberVariable() {}
       int memberVariable;
};

Will always initialize the int to zero. If the member variables were other primitive types they would also have specific initialization values. For instance, the following types are initialized, through value initialization like so:

bool = false
float = 0.0f
enum = (enum type)0
pointer = null pointer
pointer to member = null member pointer

Be extremely careful when working with data that is not explicitly initialized. One last thing, consider the following code

map<string, int> myMap;
cout << myMap["Foo"];

This code not only will always initialize the integer to 0, but it will also insert 0 into the map. Just to quickly recap, primitive data types are undefined if not initialized, but in some instances such as with a struct or map value initialization will initialize the primitive data with a specific value.

8 Comments

"Primitive data-types in C++ do not have initializers" This is oversimplified and is likely to lead to dangerous misconceptions. "not initialized" No. Well, not quite. It's called default-initialization but yes the result is an indeterminate value (C++11 8.5/11). "are undefined" No. Indeterminate. "structs" C++ does not have structs. "value initialization" Correct. The key point is the different kind of initialization used. Also you have some comma splices in your prose.
Primitive datatypes are not initialized to any value by default. They do not have default construction. They do, in some instances, have value construction. The distinction you are trying to make between an undefined and indeterminate behavior is preposterous. As per the C++ 11 standard undefined behaviors is defined as: "...nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements" essentially meaning an error in either logic or state has occurred, and the result is unknown. I never said structs were from C++.
"The distinction you are trying to make between an undefined and indeterminate behavior is preposterous." I didn't make the distinction, the standard did. If you think that is preposterous, you are of course free to raise an objection on the ISO working group mailing list.
"I never said structs were from C++." If you already know this, then why did you talk about structs on a C++ question? Now that's preposterous!
No. It is not possible to create a struct in C++. It is only possible to create a class using the inherited struct keyword. The code you have shown contains a class. C++ does not have structs. Further reading: stackoverflow.com/a/36917400/560648 stackoverflow.com/a/34108140/560648
|
9

Yes, the default value will be the default of that type. If you want another default, you can create a class that behaves like an int but has a different default constructor.

Comments

3

The default value of the map<int,int> will be 0;

if you would like to change it to -1 then following method can help.

#include <bits/stdc++.h>
using namespace std;
  
struct AnotherVal{
    int value = -1; // can be changed as per requirement 
};
  

int main()
{
    map<int, AnotherVal> tempmap;
    cout << tempmap[1].value << endl;
  
    return 0;
} 

output:

-1

Hope, this will helps you!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.