class object initialisation

G

Gary Labowitz

int i =1; does exaclty the same as
int i;
i=1;

Now this may be the crux of the issue. Is
int i = 1;
the same as
int i;
i=1;
?????
I'm on unfirm ground here, but in my youth I knew of compilers that treated
int i = 1; as a statement leading to compiling the area to be used by the
program into the executable with the value of the area already set to 1.
This meant that when the program was loaded, so was the area for i, already
initialized to 1. There was no code run to "initialize" the area; it started
life with the bits already set for that type's 1.

Does this happen at all with current C++ compilers? Say, with globals? Or
constants? (I really don't know, just asking.)
 
G

Gary Labowitz

Yes. "Indeterminate value" implies: it is an int, but with some garbage
value in it; while the truth is: it is a place for an int, with no int in
it.

Still disagree. An int with some bits in it that I didn't know would be
there ("indeterminate value") is still an int value. Display it and you will
see what value of int it is -- and not to your liking, perhaps, but still an
int. [Translation: all bit combinations in an area declared as an int ARE
int's.] This is because the compiler generates code that picks up the
number of bytes it uses for an int and interprets the bits in there as the
value. Just because you don't know what is in that area doesn't make it not
an int value.
 
G

Gary Labowitz

White Wolf said:
tom_usenet wrote:
[SNIP]
Yes, when you don't give an initializer, it is still initialized.
"Initializer" and "Initialization" are different things. Even if you
don't use an initializer, initialization still takes place.

Initialization is the action. An action of giving a determined value to
some object. If this is not done, well, then it is not initialized.

Now this raises a new issue. Does the compiler keep track of whether or not
a variable that it has allocated has yet had a value assigned to it? In
Java, for example, they do. Does C++?

I have operated on the assumption that when a variable is displayed, the
complier does not know at that point in code whether or not the area of the
variable has been stored into. To do that it would either 1) have some sort
of table of variables which has flags indicating whether or not the variable
had been assigned, or 2) have a set of bits in that variable that indicated
"this variable is empty." But I believe (see other posts) that any bit
combination in a variable can be interpreted as a value of the type of that
variable. Perhaps THIS is wrong.

Can, for example, a 4-byte int contain 1 bits in the high order half? Or
will the compiler simply ignore them since only the low order half can
contain the range of an int? I have always expected the compiler to ignore
the high order half. (For all I know the middle two bytes of a 4-byte int
contain the value of the int!)
 
A

Attila Feher

Gary Labowitz wrote:
[SNIP]
This looks like fun, so I'll take my stab at it.

:) We have way too much time on our hands. ;-)
When a variable is made available to a program,
the compiler must have generated code that sets
aside some area of memory for use by the
program.

OK. Let's change memory to something what can be written in the standard...
let's call it storage.

Now we have to obfuscate your sentence, since if just anybody could
understand it (langauge) lawyers (like us ;-) ) would be out of business.
Variable is for example a very bad name, because programmers actually
understand what it means. Also it is not appropriate here: the process we
are going to describe is also applicable to unnamed temporaries, and those
are not variables.

In C++ the creation of an object is done in two steps, one of which is
optional for objects of POD types. In the first step appropriate (size,
alignment) storage is assigned to the object.
If the generated code of the compiler also puts a
predetermined value in the area of memory, this is called
initialization.

The second, optional for POD types, step is initialization.
I.e. the memory allocated to the variable, if
examined with (say) a cout << operation, will show a value that the
programmer specified in the declaration that requested the
allocation. However, if the programmer did not specify an initial
value in the declaration, all bets are off. The initial value of the
variable could be anything and is usually whatever was in the memory
area prior to its being used as the variable being declared.

Without initialization it is not guaranteed that the object represents a
valid value for its own type, therefore it is results in undefined behavior
(behaviour for Europeans) if the object is used as an rvalue.

Initialization might happen different ways. Initialization can take the
form of explicit initializer or implicit initialization.
For certain structures, the compiler will zero-initialize members
implicitly, without the programmer having to specifically declare an
initial value.

(list cases of implicit initialization)
In the case of arrays, for example, if fewer initial
values are provided than the array can store, zero-initialiation will
be done for the remaining array elements.

Once the variable is available to the program, any movement of a
different value into the variable, such as with an assignment
operation, is called assignment.

Storage belonging to objects of POD types might stay in an uninitialized
from until an initial rvalue of a correct type has been assigned to it.
[
int i; // Storage assigned, uninitialized
int j=i; // Undefined behavior, i is not initialized
i = 12; // After the ; i is initialized to 12 using assignment
]
The entire issue is: What is in the variable immediately
after its "creation?"

An uninitialized object, just like with classes. When the operator new
returns it points to a well aligned and big enough storage area, but this
storage area does not yet the conform to the requirements of its final type.
If it is a determinate value, specified by the
programmer, it has been "initialized" by the compiler.

And for PODs this initialization is done by the compiler in the form of
"first assignment". :)
[Note: by "memory area" I do not exclude use of registers, data
bases, or any other mechanism any given compiler chooses to use for
variable storage.]

It is called storage in the standard (for that very reason, that it might
not be RAM, which we usually think about when we say memory).
Does this make sense to anyone?

Sort of. :)
 
A

Attila Feher

Gary said:
Now this may be the crux of the issue. Is
int i = 1;
the same as
int i;
i=1;
?????

Not by the current wording of the standard:

int i = 1; // i is created and initialized to a determined value

// assuming i is automatic
int i; // i is created and initialized to an indeterminate value
// IMHO this should be not-initialized
i=1; // i is assinged a determinate value

IMHO if there is nothing between the two lines above it is tha same thing.
I'm on unfirm ground here, but in my youth
I knew of compilers that treated int i = 1;
as a statement leading to compiling the area
to be used by the program into the executable
with the value of the area already set to 1.

Not for automatic objects, which are at hearth of this discussion. The
"stack" does not exist compile time. It will become an assignment runtime.
This meant that when the program was loaded, so was
the area for i, already initialized to 1.

If i is global, yes.
There was no code run to "initialize" the area;
it started life with the bits already set for
that type's 1.

Can onyl happen if i can be assigned storage during compilation. That is
not the case with automatic (stack) variables.
Does this happen at all with current C++ compilers? Say, with
globals? Or constants? (I really don't know, just asking.)

With globals it does. With (integral) constants: they usuallay have no
storage in C++.
 
A

Attila Feher

Gary said:
Still disagree. An int with some bits in it that I didn't know would
be there ("indeterminate value") is still an int value.

Really? How about a computer with a 60 bits int, which stores it in a 64
bits storage area with 4 bits of CRC?
Display it and you will see what value of int it is

Nope. Using that int as an rvalue is undefined behavior. Using the
Deathstation 9000 computer displaying such an int value will cause your
house to burn down or your mother-in-law moving in permanently with you -
depending on the operating system version.
-- and not to your liking, perhaps, but still an int.

That is the whole idea: it is *not* necessarily an int!
[Translation: all bit combinations in an
area declared as an int ARE int's.]

It is *not* required by the standard.
This is because the compiler
generates code that picks up the number of bytes it uses for an int
and interprets the bits in there as the value. Just because you don't
know what is in that area doesn't make it not an int value.

Wrong.
 
A

Attila Feher

Gary said:
Disagree. The type of a variable specifies two things: the size of
memory to be accessed and the encoding of the bits in that area.
Yes.

As far as I know, there are not "invalid" combinations of bits for
a type.

Wrong. There is nothing in the C++ standard which requires this. A
platform is free to represent an integer on 128 bits with 64 bits for value
and 64 bits for checksum.
Whatever is in there is interpreted according to the encoding
of the type.

It does not necessarily have a meaning. ints aside, this is especially true
with pointers. An implementation is free to encode the pointed type into
the pointer's bit value.
The value this results in is usually garbage, but is
still a value of the type.
Wrong.

Having said that, I wonder if bool types MUST be either all ones or
all zeros.

Do not wonder. Read the standard. It does not. And indeterminate value
for a bool does not need to represent either true or false. It is in there.
Would a bool containing mixed bits confuse a formatter
(like cout) or would it just say "Hmmm, not all zeros --- therefore,
true!"

Implementation defined.
 
A

Attila Feher

Gary said:
White Wolf said:
tom_usenet wrote:
[SNIP]
Yes, when you don't give an initializer, it is still initialized.
"Initializer" and "Initialization" are different things. Even if you
don't use an initializer, initialization still takes place.

Initialization is the action. An action of giving a determined
value to some object. If this is not done, well, then it is not
initialized.

Now this raises a new issue. Does the compiler keep track of whether
or not a variable that it has allocated has yet had a value assigned
to it? In Java, for example, they do. Does C++?

Nope. In the name of efficiency (the route of all evil) it does not.
I have operated on the assumption that when a variable is displayed,
the complier does not know at that point in code whether or not the
area of the variable has been stored into.

It does not, only for statics in a function. Valgrind might tell you, but
only if you try to make a decision using that value.
To do that it would either
1) have some sort of table of variables which has flags indicating
whether or not the variable had been assigned, or 2) have a set of
bits in that variable that indicated "this variable is empty." But I
believe (see other posts) that any bit combination in a variable can
be interpreted as a value of the type of that variable. Perhaps THIS
is wrong.

It is. It is true on many architectures but it is not a rule, it just
happens to be that way.
Can, for example, a 4-byte int contain 1 bits in the high order half?
Or will the compiler simply ignore them since only the low order half
can contain the range of an int? I have always expected the compiler
to ignore the high order half. (For all I know the middle two bytes
of a 4-byte int contain the value of the int!)

That is complete bull-byproduct.
 
T

tom_usenet

Well, in my poor English vocabulary that is non-determinable. Indeterminate
is (for me) something we do not know for sure (like what will rand put
there) but we can find out later. Non-determinable is OTOH something which
cannot be examined.

Indeterminate:
a)Not precisely determined, determinable, or established: a person of
indeterminate age.
b)Not precisely fixed, as to extent, size, nature, or number: an
indeterminate number of plant species in the jungle.
c)Lacking clarity or precision, as in meaning; vague: an indeterminate
turn of phrase.
d)Not fixed or known in advance: an indeterminate future.
e)Not leading up to a definite result or ending: an indeterminate
campaign.

So indeterminate can mean either not precisely determined or not
determinable. The standard clearly uses it to mean not determinable
(since you aren't allowed to examine the value).
Where is that required by the standard?
3.9.1/1
Also:
http://std.dkuug.dk/jtc1/sc22/wg21/docs/cwg_active.html#129


Again a bit of a mystery. delete take a *copy* of the pointer. So it
cannot change it at all. So the value of the pointer *is* determined, we
exactly know what value it has. Only this value is not to be dereferenced.

It is indeterminate since, although the bit pattern won't have
changed, valid bit patterns for pointers might have been changed by
the delete.

Tom
 
W

White Wolf

tom_usenet said:
Indeterminate:
a)Not precisely determined, determinable, or established: a person of
indeterminate age.

He *has* an age, we just do not know it. It is not like he has no such
thing as an age. While uninitialized PODs may have such bits in their
storage that they have no value whatsoever.
b)Not precisely fixed, as to extent, size, nature, or number: an
indeterminate number of plant species in the jungle.

So many, we cannot/will not count it. Again: it is an existing, valid
value.
c)Lacking clarity or precision, as in meaning; vague: an indeterminate
turn of phrase.

This - if I understand it properly - is again closer to unknown than to
non-existing (which is the value of an uninitialized POD)
d)Not fixed or known in advance: an indeterminate future.

Again: will be known, only later
e)Not leading up to a definite result or ending: an indeterminate
campaign.

This meaning is about an action or series of actions. Cannot really be
applied to a value.
So indeterminate can mean either not precisely determined or not
determinable.

Not determinable from the viewpoint of the observer! BIG difference. The
person of indeterminate age *has* an age. A indeterminate campaign *will*
have an end and a result - if not later than on judgment day.
The standard clearly uses it to mean not determinable
(since you aren't allowed to examine the value).

I see no such meaning in the listed definitions above. Each and every of
those things above objectively *exist* we just could not, will not, do not
want to determine. OTOH the value of an int, which is built from bits which
makes no sense as an int, is just not there. It does not exist. It is not
an int. There is no sense in talking about it as an int. Since there is no
sense talking about it as an int there is not much sense talking about its
value.

Should not be. c is used as an rvalue there...

Weird! Why would someone ask for such an arbitrary requirement?

Hmmmm. This is baaad. I mean this reads: in C++ it is not even not
guaranteed that a variable (POD) has a valid value until it is given one,
but it is not even required to *exist* in its *exclusive* storage... While
I completely agree with what is written in the DR/TR/xR(?) I believe that
this is more than surprising. So not only (real) initialization is optional
but even creation...
It is indeterminate since, although the bit pattern won't have
changed, valid bit patterns for pointers might have been changed by
the delete.

It is not indeterminate. I know what it is. I can determine it. It is
just not valid to be *dereferenced*. I can even store away together with
sand from the Oregon dunes, my childhood golden hair and photos of my late
girlfriend (she is alive, she just never arrives in time) into an in-memory
application log (possibly as a void*). So the pointer has a *valid* value.
I can copy it around. (at lest I hope so). I just cannot dereference it.
If I cannot (even copy it around - which would make sense) then I dunno
enough C++. :) Which is true, but this would further prove it. BTW I
never did copy it around, only it could make sense for such logging
purposes.
 
F

foo

jeffc said:
And there are plenty of things you can't. You can put expressions in there,
but you can't put statements in there. You can't call functions (alone),
you can't use for or while loops, you can't... well, you already know what
you can't do.

Why would you want to put functions alone in an initialize list?
The point of the initialize list is to initialize variables. It's not
for replaceing the constructor's function body.
If you have while-loop logic or any other logic that you need for the
initializaiton of your variable, you can easily put that inside a
function that can be used to initialize the member variable.
Example:
class foo
{
public:
foo(const char* Name, int x)
:m_Msg(SomeFunc1(Name)), m_Data(SomeFunc2(Name, x))
{
}
const std::string m_Msg;
const std::string m_Data;
private:
std::string SomeFunc1(const std::string &Name){
return "Hello " + Name;
}
std::string SomeFunc2(const std::string &Name, int x)
{
std::string Data;
for (int i = 0;i < x;++i) Data += Name + " ";
return Data;
}
};


int main(int argc, char* argv[])
{
foo MyFoo("Axter", 3);

cout << MyFoo.m_Msg << endl;
cout << MyFoo.m_Data << endl;

system("pause");
return 0;
}
 
G

Gary Labowitz

Attila Feher said:
Wrong. There is nothing in the C++ standard which requires this. A
platform is free to represent an integer on 128 bits with 64 bits for value
and 64 bits for checksum.


It does not necessarily have a meaning. ints aside, this is especially true
with pointers. An implementation is free to encode the pointed type into
the pointer's bit value.


Do not wonder. Read the standard. It does not. And indeterminate value
for a bool does not need to represent either true or false. It is in there.

Implementation defined.

Thank you. If this be the case, then all my musings are incorrect. Hmm...
check sum bits in a value. Yes, it could. Then invalid bit combinations
could exist. All resulting in undefined behavior I should think.
Back to the drawing board!!!
[Gee, what did we go back to before they invented drawing boards?]
 
G

Gary Labowitz

Attila Feher said:
Gary Labowitz wrote:
[SNIP]
This looks like fun, so I'll take my stab at it.

:) We have way too much time on our hands. ;-)
When a variable is made available to a program,
the compiler must have generated code that sets
aside some area of memory for use by the
program.

OK. Let's change memory to something what can be written in the standard...
let's call it storage.

Now we have to obfuscate your sentence, since if just anybody could
understand it (langauge) lawyers (like us ;-) ) would be out of business.
Variable is for example a very bad name, because programmers actually
understand what it means. Also it is not appropriate here: the process we
are going to describe is also applicable to unnamed temporaries, and those
are not variables.

In C++ the creation of an object is done in two steps, one of which is
optional for objects of POD types. In the first step appropriate (size,
alignment) storage is assigned to the object.
If the generated code of the compiler also puts a
predetermined value in the area of memory, this is called
initialization.

The second, optional for POD types, step is initialization.
I.e. the memory allocated to the variable, if
examined with (say) a cout << operation, will show a value that the
programmer specified in the declaration that requested the
allocation. However, if the programmer did not specify an initial
value in the declaration, all bets are off. The initial value of the
variable could be anything and is usually whatever was in the memory
area prior to its being used as the variable being declared.

Without initialization it is not guaranteed that the object represents a
valid value for its own type, therefore it is results in undefined behavior
(behaviour for Europeans) if the object is used as an rvalue.

Initialization might happen different ways. Initialization can take the
form of explicit initializer or implicit initialization.
For certain structures, the compiler will zero-initialize members
implicitly, without the programmer having to specifically declare an
initial value.

(list cases of implicit initialization)
In the case of arrays, for example, if fewer initial
values are provided than the array can store, zero-initialiation will
be done for the remaining array elements.

Once the variable is available to the program, any movement of a
different value into the variable, such as with an assignment
operation, is called assignment.

Storage belonging to objects of POD types might stay in an uninitialized
from until an initial rvalue of a correct type has been assigned to it.
[
int i; // Storage assigned, uninitialized
int j=i; // Undefined behavior, i is not initialized
i = 12; // After the ; i is initialized to 12 using assignment
]
The entire issue is: What is in the variable immediately
after its "creation?"

An uninitialized object, just like with classes. When the operator new
returns it points to a well aligned and big enough storage area, but this
storage area does not yet the conform to the requirements of its final type.
If it is a determinate value, specified by the
programmer, it has been "initialized" by the compiler.

And for PODs this initialization is done by the compiler in the form of
"first assignment". :)
[Note: by "memory area" I do not exclude use of registers, data
bases, or any other mechanism any given compiler chooses to use for
variable storage.]

It is called storage in the standard (for that very reason, that it might
not be RAM, which we usually think about when we say memory).
Does this make sense to anyone?

Sort of. :)

[Last time fully quoted]
Well, I like your obfuscation! I didn't understand anything! It's ready for
publication!
On the serious side, the fact that there are invalid combinations of bits
for types introduces a whole new complexity for me, and makes the standard
almost unbearably complex. Oh well, reality must be faced.
On the whole, I rather prefer Java: nine simple types to learn about, all
well defined with regard to bit usage and size, no surprises.
Thanks for your patience.
 
A

Alexander Terekhov

White Wolf wrote:
[...]
It is not indeterminate. I know what it is. I can determine it. It is
just not valid to be *dereferenced*. I can even store away together with
sand from the Oregon dunes, my childhood golden hair and photos of my late
girlfriend (she is alive, she just never arrives in time) into an in-memory
application log (possibly as a void*). So the pointer has a *valid* value.
Nope.

I can copy it around. (at lest I hope so).

Nope. You can't copy it AS POINTER. std::vector<unsigned char> will
work, though. ;-)

regards,
alexander.
 
A

Alexander Terekhov

Attila said:
Not even as void?

void pointer? It will also not work. You'll hit undefined
behavior as soon as you try to 'use' deleted/freed pointer
as pointer... assignment of valid pointer value and access
via unsigned char lvalue is totally OK, though. In short,

auto int i; // indeterminate (may be a trap)
auto void * p; // indeterminate (may be a trap)
auto unsigned char c; // indeterminate (unspecified;
// shall NOT be a trap)

IIRC.

regards,
alexander.
 
A

Attila Feher

Alexander said:
void pointer? It will also not work. You'll hit undefined
behavior as soon as you try to 'use' deleted/freed pointer
as pointer...

But that was the *whole* point: I do *not* want to use it as a pointer. I
never want to dereference it or apply arithmetics to it.
 

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
474,141
Messages
2,570,818
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top