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:
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
Lindley
March 10th, 2008, 06:02 PM
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().
xorbe
March 10th, 2008, 06:07 PM
(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
/**
* @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.
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).
xorbe
March 10th, 2008, 06:15 PM
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 ofstruct foo {
foo(){}
int x;
}you will get garbage, because it is non-POD.
jlou
March 10th, 2008, 06:17 PM
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.
Paul McKenzie
March 10th, 2008, 06:22 PM
(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:
x[0] = 10;
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
xorbe
March 10th, 2008, 06:26 PM
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:
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
jlou
March 10th, 2008, 06:33 PM
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,
JasonYes.
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.
xorbe
March 10th, 2008, 06:40 PM
That's awesome, many thanks!
xorbe
March 10th, 2008, 06:52 PM
As a follow-up question, what about:
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...)
jlou
March 10th, 2008, 07:01 PM
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).
xorbe
March 10th, 2008, 07:02 PM
I read that even global scope, bss can be non-zero given the right gcc flags... (but you have to be aiming for that)
jlou
March 10th, 2008, 07:04 PM
You can do lots of non-standard things with the right compiler options set. ;)
xorbe
March 10th, 2008, 07:16 PM
Yeah, foo x; is uninitialized (as expected), and foo y = foo(); is initialized, according to Valgrind. Wow I feel silly... huh.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.