what's the difference between value-initialization and default-initialization?

J

Jess

Hello,

I understand the default-initialization happens if we don't initialize
an object explicitly. I think for an object of a class type, the
value is determined by the constructor, and for the built-in types,
the value is usually garbage. Is this right?

However, I'm a bit confused about value-initialization, when does it
happen, and what kind of values are assigned to objects?

Thanks.
 
G

Gianni Mariani

Jess said:
Hello,

I understand the default-initialization happens if we don't initialize
an object explicitly. I think for an object of a class type, the
value is determined by the constructor, and for the built-in types,

Not only built-in types but POD (plain old data) types.
the value is usually garbage. Is this right?

Yes, unless you use a () in your initialization of the POD members/data.
However, I'm a bit confused about value-initialization, when does it
happen, and what kind of values are assigned to objects?

You assign whatever value type you enable. Usually, a class has a copy
constructor and an assignment operator available.

i.e.

struct Z
{
Z() {} // YYY
Z( const char * ) {}
Z & operator=( const char * ) {} // XXX
};

Z x( "HI" );

Z y( x ); // copy constructor (compiler provided YYY)

int main()
{

y = x; // assignment operator (compiler provided)

y = "THERE"; // assignment operator XXX

}
 
J

Jess

Not only built-in types but POD (plain old data) types.

What is POD?
Yes, unless you use a () in your initialization of the POD members/data.
Again, could you please give more explanation?
You assign whatever value type you enable. Usually, a class has a copy
constructor and an assignment operator available.

i.e.

struct Z
{
Z() {} // YYY
Z( const char * ) {}
Z & operator=( const char * ) {} // XXX

};

Z x( "HI" );

Z y( x ); // copy constructor (compiler provided YYY)

int main()
{

y = x; // assignment operator (compiler provided)

y = "THERE"; // assignment operator XXX

}
It'd be very helpful if you could explain the example. Thanks a lot!
 
M

Mumia W.

Hello,

I understand the default-initialization happens if we don't initialize
an object explicitly. I think for an object of a class type, the
value is determined by the constructor, and for the built-in types,
the value is usually garbage. Is this right?

However, I'm a bit confused about value-initialization, when does it
happen, and what kind of values are assigned to objects?

Thanks.


#include <cstdio>
#include <cstdlib>

class Foo {
public:
int value;
const char * str;

void print (FILE * fh) {
fprintf(fh, "%d => %s\n", value, str);
}
};

int main ()
{
Foo myfoo = { 10, "Hello" };
myfoo.print(stdout);

return EXIT_SUCCESS;
}

-----end-code--------

Notice that myfoo was initialized by values written in the style used to
initialize POD (plain old data--known in C as 'structs').
 
G

Gianni Mariani

Jess said:
What is POD?

Google "POD (plain old data)" - here is an "I'm Feeling Lucky Link"

http://www.google.com/search?hl=en&q=POD+Plain+Old+Data&btnG=Google+Search
Again, could you please give more explanation?


Consider this:

struct A { int x; A() : x() {} };

struct B { int x; };

int main()
{
A a;
B b;

return a.x == b.x;
}

The value of a.x is always 0. The value of b.x is indeterminate or
uninitialized.

This applies for all POD types.

B is a POD type;

consider:
B b( B() );

.... b.x is now initialized.

Note that if you had written:
B b(); // function declaration of function b() returning a B.
.... nasty little issue for newbies...

It'd be very helpful if you could explain the example. Thanks a lot!

You need to read the chapter on constructors in C++ in your favorite
book and come back.
 
J

James Kanze

I understand the default-initialization happens if we don't initialize
an object explicitly. I think for an object of a class type, the
value is determined by the constructor, and for the built-in types,
the value is usually garbage. Is this right?

Written with a hyphen, no. "default-initialization" is a
technical term, defined and used in the standard:

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.

Note, however, that variables aren't default-initialized by
default:).
However, I'm a bit confused about value-initialization, when
does it happen, and what kind of values are assigned to
objects?

Again, a technical term used in the standard (or at least the
latest draft). I'll admit that when reading the standard, I
can't quite make out what the intended difference between
default initialization and value initialization is supposed to
be. The original version (ISO 14882:1998) doesn't have value
initialization.

I suspect that the intent is to ensure that zero initialization
occurs when the type has a non trivial implicit constructor.
The exact wording is:

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 baseclass component of T is
value-initialized;

-- if T is an array type, then each element is
value-initialized;

-- otherwise, the object is zero-initialized

Basically, what gets added is the second point. If I have a
class something like:

class C
{
public:
virtual ~C() {}
int x ;
} ;

It's not a POD, but it doesn't have a user defined
constructor, so value-initialization guarantees that x is
set to 0, whereas default-initialization doesn't.

And to quote the standard: "An object whose initializer is
an empty set of parentheses, i.e. () shall be
value-initialized." (In the latest draft;
default-initialized in the 1998 version of the standard.)
 
R

Ron Natalie

James said:
Note, however, that variables aren't default-initialized by
default:).

One of the most stupid features of C++. Variables aren't always
default-initialized.
I suspect that the intent is to ensure that zero initialization
occurs when the type has a non trivial implicit constructor.
The exact wording is:
Well, more specifically, it makes the behavior consistent when
the object contains objects of possibly non-POD type. Before
this concept was defined you couldn't figure out how:

struct S {
int i;
T t;
} s;

would be initialized unless you knew what T was.
 
J

Jess

struct A { int x; A() : x() {} };

struct B { int x; };

int main()
{
A a;
B b;

return a.x == b.x;

}

The value of a.x is always 0. The value of b.x is indeterminate or
uninitialized.

This is called default-initialization, right?
consider:
B b( B() );

... b.x is now initialized.

I don't quite understand this... "B()" creates a temporary object and
it's passed to a copy-constructor to initialize "b", and the copy
constructor tries to copy "x" value of the tmp object to "b"'s "x".
However, what is the value of tmp object's "x"?
You need to read the chapter on constructors in C++ in your favorite
book and come back.

I did read Accelerated C++, but am still confused. In order to
clarify the matter, here's what I think, not sure whether they are
right/wrong:

1. Default initialization is used when we create an object using the
form "T t", where T can be a POD type or class type. If this happens,
the following occurs:
a. if T is POD, then "t" is garbage value
b. if T is class, then it's default constructor is invoked. If
there's no default contructor, the compiler will synthesize one.
(i). If there's a default constructor, then all T's POD member data is
initialized according to the constructor initializer list; any POD
member not mentioned in the initializer list gets default-init, with
garbage value. If T has a class-typed member (say of type A), then
A's default constructor is called and if A has no default constructor,
then the synthesized constructor will be called. FInally, the
constructor's body is entered.
(ii). If there is no default constructor, then the synthesized
constructor will be called. All POD member gets garbage data and
class members have their default constructor (or synthesized default
constructors) invoked.

Is this what happens to default-init? Moreover, to init POD member in
the constructor initializer, I can do things like "x(10)" and also
"x()" where "x" is an int, is this right? If "x()" is used, then "x"
gets value-init to 0?

2. Value-initialization happens if a constructor is explicitly invoked
like "T t(arg)", or when we invoke copy constructor. For a class type
object:
a. if it's created by invoking a constructor like "T t(arg)", then all
its POD member gets initialized according to the constructor
initializer; any POD member not mentioned gets value-init to 0. But
what happens to those class-typed members? Are their default
constructors (or synthesized one) called? I think after all these are
done, the constructor's body is entered.
b. if the T object is created through copy constructor, then the
values of the existing objects are copied into the new object.
However, what if we have an example like "B b(B())"? what's the value
of the tmp object?

3. To value-init a POD object, I think the only way is to do something
like:

int n = int();
is this right?

4. The book Accelerated C++ also says that if an object is used to
init a container element, either as a side effect of adding new
element to a "map", or as the elements of a container defined to have
a given size, then the members will be value-initialized. I checked
it through an example,

struct A{
int x;
};

int main(){
A a[10];
return 0;
};

Then I found out each element in a has it's "x" value as 0. I think
this is what the author of the book meant. Then I tried another
example:

int main(){
int b[10];
return 0;
}

This time, each element in b has garbage value. Isn't each member of
b supposed to be value-init to 0?

I'd really appreciate it if some of you could answer my questions and
point out my mistakes and also let me know the points I overlooked.
Thanks.
Jess
 
J

Jess

B b(B());

is a declaration of a funciton. There is no b.x. 'b' is a function.

But in your previous message, you mentioned "b.x" is initialized?
Also, "B()" calls B's default constructor, and the result is a B
object. When we use this temporary object to "B b(B())", aren't we
calling the copy-constructor?

Thanks
Jess
 
R

Ron Natalie

Jess said:
But in your previous message, you mentioned "b.x" is initialized?
Also, "B()" calls B's default constructor, and the result is a B
object. When we use this temporary object to "B b(B())", aren't we
calling the copy-constructor?

You can't call constructors, constructors are called by object creation.
The above is not an object creation. It's a definition of a function
called "b' which takes a paramter of type B and returns B.
 
A

Alf P. Steinbach

* Ron Natalie:
You can't call constructors, constructors are called by object creation.

Sort of. You might argue that that statement is purely about
terminology. But even so, the standard uses the terms "call" and
"invoke", the language's creator does so, I do so, and in short, the
statement is just plain wrong no matter whether it's about what one can
do or about established terminology.

An accurate statement is that outside a constructor initializer list you
can't call a constructor on existing storage, except by using low-level
(not type safe) shenanigans[1].

A more useful but not quite as accurate statement is that with at least
one user-defined constructor C++ effectively provides a construction
guarantee where each object (including each sub-object) receives exactly
one constructor call, which happens before anything else.

The above is not an object creation. It's a definition of a function
called "b' which takes a paramter of type B and returns B.

Right.

And the reason has nothing to do with constructor calls, but with an
ambiguity in the grammar, which the standard requires is always resolved
in favor of a function declaration, if possible.

By including additional parentheses an interpretation as a function
declaration is no longer possible,

B b((B()));

but there's a limit to how subtle code one should write, so it's better
to do the straightforward

B b;

or, in some contexts,

B b = B();

Cheers,

- Alf


Notes:
[1] Low-level shenanigans include in-place construction.
 
O

Old Wolf

but there's a limit to how subtle code one should write, so it's better
to do the straightforward

B b;

or, in some contexts,

B b = B();

Doesn't the latter require an accessible copy constructor?
 
J

Jess


So "B b(B());" is a definition of "b"? Then it's return type is "B"
and its argument type "looks like" B to me. I'm saying it "looks
like" "B" because it's paramenter is "B()" instead of the standard
format like "type arg". Moreover, if this is a definition of "b",
then why can I receive a B object after this execution, where's the
invocation of the function "b"?
but there's a limit to how subtle code one should write, so it's better
to do the straightforward

B b;

or, in some contexts,

B b = B();

I think the default constructor is called in the first case. For the
second case, a default constructor is called for "B()", then a copy-
constructor is called (by the compiler) to copy the "B" to a temporary
result, and then another copy-constructor is called to copy the
temporary B object to "b" to initialize "b", is this right? In terms
of value-initialization and default-initialization, are these two
examples the same? I think the first one looks like default-init and
the second one looks like value-init. I'm still not quite sure about
the differences.

Could someone answer my questions that I posed earlier and point out
whether I've made mistakes about value- and defaul-initialization? :)
Perhaps I should start a new thread in case it's not obvious what my
questions are. :)
 
O

Old Wolf

Must have been a long day for Ron and Alf. The parameter to 'b'
has type 'pointer to function taking no arguments and returning B'.
It is the same as:
B b( B (*)() );
So "B b(B());" is a definition of "b"? Then it's return type is "B"
and its argument type "looks like" B to me.

Looks can be deceiving :)
I'm saying it "looks like" "B" because it's paramenter is "B()"
instead of the standard format like "type arg".

"type arg" is not a "standard format". Some simple declarations
look like that, but the syntax for declarations is more complicated,
with "arg" sometimes coming in between different parts of "type".
For example, int x[5]
Moreover, if this is a definition of "b", then why can I receive a B
object after this execution, where's the invocation of the function "b"?

Huh? (Post some code to illustrate what you mean).
I think the default constructor is called in the first case. For the
second case, a default constructor is called for "B()", then a copy-
constructor is called (by the compiler) to copy the "B" to a temporary
result, and then another copy-constructor is called to copy the
temporary B object to "b" to initialize "b", is this right?

You have one step too many (I think). A temporary object is default-
constructed, and then 'b' is copy-constructed from that object.
 
R

Ron Natalie

Alf said:
Sort of. You might argue that that statement is purely about
terminology.

And the standard has non-ambiguous terminology.
But even so, the standard uses the terms "call" and
"invoke",

But doesn't refer to programs being able to call constructors. It
specifically states to the contrary.

I don't see why you insist on continually inserting this non-sequitor
incorrect argument in discussions. It just confuses the issue.
An accurate statement is that outside a constructor initializer list you
can't call a constructor on existing storage, except by using low-level
(not type safe) shenanigans[1].

You can't even do it inside a constructor initializer list (if you're
talking about the mem-init list), the belief that such a list is a
constructor call further confuses the fact that the mem-initializers
have no bearing at all on constructor invocation order.
A more useful but not quite as accurate statement is that with at least
one user-defined constructor C++ effectively provides a construction
guarantee where each object (including each sub-object) receives exactly
one constructor call, which happens before anything else.

That is correct IF you remove the words user-defined.
And the reason has nothing to do with constructor calls, but with an
ambiguity in the grammar, which the standard requires is always resolved
in favor of a function declaration, if possible.

Correct, but the original poster thought he was calling a constructor
which isn't true by either yours or the official standard definition.
 
J

Jess

Must have been a long day for Ron and Alf. The parameter to 'b'
has type 'pointer to function taking no arguments and returning B'.
It is the same as:
B b( B (*)() );

Is it ok to ignore the "*" while still have the same meaning?
"type arg" is not a "standard format". Some simple declarations
look like that, but the syntax for declarations is more complicated,
with "arg" sometimes coming in between different parts of "type".
For example, int x[5]

Indeed, :)
Huh? (Post some code to illustrate what you mean).

I made the mistake of thinking this init "b" and realised I was
wrong....
You have one step too many (I think). A temporary object is default-
constructed, and then 'b' is copy-constructed from that object.

I see, so the additional temp object is only created if a function is
returning, is it right?

Thanks
Jess
 
J

Jess

Correct, but the original poster thought he was calling a constructor
which isn't true by either yours or the official standard definition.

I made that mistake because in the constructor initializer, we can do
something similar:

struct A{
int x;
int y;
A():x(1),y(){}
};

I then thought we can create an A object by "A a()". I get it now.
thanks!

Jess
 
A

Alf P. Steinbach

* Ron Natalie:
And the standard has non-ambiguous terminology.


But doesn't refer to programs being able to call constructors. It
specifically states to the contrary.

It specifically uses those terms about source code calls in numerous
places. As far as I know it doesn't state anything to the contrary, and
that's up at the 99.99% confidence level since this has been discussed
numerous times, at length. I suggest you look up the most recent thread
about this in clc++m (James Kanze and me).

I don't see why you insist on continually inserting this non-sequitor
incorrect argument in discussions. It just confuses the issue.

Sorry, that's not even wrong.

An accurate statement is that outside a constructor initializer list
you can't call a constructor on existing storage, except by using
low-level (not type safe) shenanigans[1].

You can't even do it inside a constructor initializer list (if you're
talking about the mem-init list), the belief that such a list is a
constructor call further confuses the fact that the mem-initializers
have no bearing at all on constructor invocation order.

Sorry, that's incorrect.

That is correct IF you remove the words user-defined.

Sorry that's incorrect. Specifically, without a user-defined constructor,

B b;

locally in a function, does not initialize B (another example is use in
a union).

The reason the statement is not quite as accurate as the previous one is
that even with a user defined constructor you can still do e.g.

B b = b;

where the compiler is permitted to optimize away the copy constructor
call; anyway, no real initialization here, but also no low-level things.

Correct, but the original poster thought he was calling a constructor
which isn't true by either yours or the official standard definition.

Consider the variant with extra parentheses: it's just a syntax issue.
 
R

Ron Natalie

Alf said:
Sorry that's incorrect. Specifically, without a user-defined constructor,

B b;

locally in a function, does not initialize B (another example is use in
a union).
There is an implicitly defined consturctor (admittedly rarely actually
causing executable code), but it depends on what the definition of B
is. This is actually the who reason the term "value initialized" was
invented.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,709
Latest member
AustinMudi

Latest Threads

Top