|
-
March 10th, 2008, 05:59 PM
#1
map<int,int> x; x[0]; // no valgrind warning?
I tried this code snippet + several variations, plus
using gcc 3.3 through 4.2, plus -00 through -03,
and Valgrind just does not throw up an uninitialized
variable warning:
Code:
#include <stdio.h>
#include <map>
int main() {
std::map<int,int> x;
printf("%d\n", x[0]);
}
I even pulled it up in gdb debugger, and nothing
writes to the memory location. I even added
x[0] = 1; at the end to verify the breakpoint worked.
updated: I made a second try and trapped the STL
writing 0 -- guess I botched the first attempt.
Yet, any such access WILL be zero initially! I'm
trying to prove that it will break to a co-worker -- but
I'm not winning so far.
What's going on? I don't see anything in the STL yet
that would guarantee such behavior for POD! Thanks,
Jason
Last edited by xorbe; March 11th, 2008 at 04:25 AM.
-
March 10th, 2008, 06:02 PM
#2
Re: map<int,int> x; x[0]; // no valgrind warning?
The [] operator creates an entry if one doesn't already exist.
To do a lookup that can't create an entry which isn't there, you have to use find().
-
March 10th, 2008, 06:07 PM
#3
Re: map<int,int> x; x[0]; // no valgrind warning?
(The example stands precisely as presented. I know
what I'm talking about here.)
Well I'll be, it is initialized by the STL!
Is this guaranteed by the STL spec somewhere?
stl_construct.h
Code:
/**
* @if maint
* Constructs an object in existing memory by invoking an allocated
* object's constructor with an initializer.
* @endif
*/
template <class _T1, class _T2>
inline void
_Construct(_T1* __p, const _T2& __value)
{ new (static_cast<void*>(__p)) _T1(__value); }
I constructed a better test, and the debugger stopped at
that point as being written by the STL.
stl_tree.h
Code:
_Link_type
_M_create_node(const value_type& __x)
{
_Link_type __tmp = _M_get_node();
try
{ _Construct(&__tmp->_M_value_field, __x); } // here
catch(...)
{
_M_put_node(__tmp);
__throw_exception_again;
}
return __tmp;
}
Last edited by xorbe; March 10th, 2008 at 06:14 PM.
-
March 10th, 2008, 06:12 PM
#4
Re: map<int,int> x; x[0]; // no valgrind warning?
 Originally Posted by xorbe
Well I'll be, it is initialized by the STL!
Is this guaranteed by the STL spec somewhere?
Yes. According to the C++ standard, an entry will be added with that key and a value-initialized value (which basically default constructs class types and zero-initializes built-in types).
Last edited by jlou; March 10th, 2008 at 06:16 PM.
-
March 10th, 2008, 06:15 PM
#5
Re: map<int,int> x; x[0]; // no valgrind warning?
 Originally Posted by jlou
Yes. According to the C++ standard, an entry will be added with that key and a default-initialized value.
But what [value]-initialized value? Does it say "zero"?
I know if you have a map of
Code:
struct foo {
foo(){}
int x;
}
you will get garbage, because it is non-POD.
Last edited by xorbe; March 11th, 2008 at 12:40 PM.
-
March 10th, 2008, 06:17 PM
#6
Re: map<int,int> x; x[0]; // no valgrind warning?
Sorry, yes. If the value type is int, then the new value will be 0. If the value type is foo above, then the default constructor for foo will be called, which does not initialize x.
It basically calls T() for the value type T.
-
March 10th, 2008, 06:22 PM
#7
Re: map<int,int> x; x[0]; // no valgrind warning?
 Originally Posted by xorbe
(The example stands precisely as presented. I know
what I'm talking about here.)
Well I'll be, it is initialized by the STL!
Is this guaranteed by the STL spec somewhere?
It isn't just the spec. The map has no choice but to create a new member for operator [].
When you do something like this:
There are two operations going on, not one. First the key is created using operator []. The second operation is the call of the assignment operator. But look at the first thing that's done -- a key is created. This is done regardless of whether there is an assignment being done or not. There is no way for the map's operator [] to anticipate that you're using [] for key creation or just as an accessor.
Regards,
Paul McKenzie
-
March 10th, 2008, 06:26 PM
#8
Re: map<int,int> x; x[0]; // no valgrind warning?
 Originally Posted by Paul McKenzie
There are two operations going on, not one. First the key is created using operator []. The second operation is the call of the assignment operator. But look at the first thing that's done -- a key is created. This is done regardless of whether there is an assignment being done or not. There is no way for the map's operator [] to anticipate that you're using [] for key creation or just as an accessor.
Regards,
Paul McKenzie
Yes, I know all that. You're missing my (er, intended) question here. I have traced the question down to this line of code in the STL:
Code:
__i = insert(__i, value_type(__k, mapped_type()));
mapped_type is _Tp which is int.
So, my ultimate question is,
why is "int()" guaranteed to be zero?
Where can I read this guarantee?
Will "bool()" always be false?
Will "type*()" always be NULL?
Thanks,
Jason
Last edited by xorbe; March 10th, 2008 at 06:28 PM.
-
March 10th, 2008, 06:33 PM
#9
Re: map<int,int> x; x[0]; // no valgrind warning?
 Originally Posted by xorbe
So, my ultimate question is,
why is "int()" guaranteed to be zero?
Where can I read this guarantee?
Will "bool()" always be false?
Will "type*()" always be NULL?
Thanks,
Jason
Yes.
Section 8.5 of the C++ standard. Paragraph 7 states:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
Paragraph 5 above it clarifies what value-initialized means:
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject is zeroinitialized;
— if T is a union type, the object’s first named data member89) is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
To default-initialize an object of type T means:
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is
ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the object is zero-initialized.
To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is
called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static data member
and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
I added bold emphasis to indicate what I think are the applicable sections.
Last edited by jlou; March 10th, 2008 at 06:35 PM.
-
March 10th, 2008, 06:40 PM
#10
Re: map<int,int> x; x[0]; // no valgrind warning?
That's awesome, many thanks!
-
March 10th, 2008, 06:52 PM
#11
Re: map<int,int> x; x[0]; // no valgrind warning?
As a follow-up question, what about:
Code:
struct foo {
int x;
int y;
};
So then, foo() implies int() inside due to a lack of a constructor?
foo x; // will the values be zero?
foo y = foo(); // what about here?
(Er, I guess I can use Valgrind again to determine this... sigh...)
Last edited by xorbe; March 10th, 2008 at 07:01 PM.
-
March 10th, 2008, 07:01 PM
#12
Re: map<int,int> x; x[0]; // no valgrind warning?
Since there is no user declared constructor, then I would imagine x and y are set to 0 when an instance of foo is value initialized. However, if an instance of foo is default initialized, then x and y will have undefined values.
Your second example will value-initialize y, but I'm not sure about the first. I believe in non-global scope it will default-initialize (and therefore leave the x and y members uninitialized).
-
March 10th, 2008, 07:02 PM
#13
Re: map<int,int> x; x[0]; // no valgrind warning?
I read that even global scope, bss can be non-zero given the right gcc flags... (but you have to be aiming for that)
-
March 10th, 2008, 07:04 PM
#14
Re: map<int,int> x; x[0]; // no valgrind warning?
You can do lots of non-standard things with the right compiler options set.
-
March 10th, 2008, 07:16 PM
#15
Re: map<int,int> x; x[0]; // no valgrind warning?
Yeah, foo x; is uninitialized (as expected), and foo y = foo(); is initialized, according to Valgrind. Wow I feel silly... huh.
Last edited by xorbe; March 11th, 2008 at 04:27 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|