Are int a; int a(); int a=0; the same?

P

PengYu.UT

Hi,

I'm wondering if the following three statements are the same or only
the last two are the same?

int a;
int a();
int a=0;

Thanks,
Peng
 
D

Daniel T.

I'm wondering if the following three statements are the same or only
the last two are the same?

int a;
int a();
int a=0;

No. This sounds remarkably like a homework/test question. Ask yourself,
what will be the value of 'a' in the first case? What will be it's value
in the last case?

As for the middle line, compare a function declaration to a variable
definition...
 
J

Jim Langston

Hi,

I'm wondering if the following three statements are the same or only
the last two are the same?

int a;
int a();
int a=0;

You missed one
int a(0);

The three you show do different things.

The first one declares a as an interger which is unitialized. Can contain
any value. Be careful, some compilers will initialize variables to 0 in
debug mode but not release mode sometimes causing hard to find errors.

The second one declares a function called a accepting no parameters and
retuning an integer.

The third one declares a as in integer and initializes it to zero.

The fourth one also declares a as an integer and initializes it to zero.

Note:
int a;
a = 0;

is different than
int a = 0;

The first case uses the assignment operator. The second case uses the
constructor.
 
J

James Kanze

You missed one
int a(0);
The three you show do different things.
The first one declares a as an interger which is unitialized.
Can contain any value. Be careful, some compilers will
initialize variables to 0 in debug mode but not release mode
sometimes causing hard to find errors.

In debug mode, I'd expect something like 0xdeadbeef.

And of course, it depends where the declarations are placed. If
they are at namespace scope, then the first one is zero
initialized.
The second one declares a function called a accepting no
parameters and retuning an integer.
The third one declares a as in integer and initializes it to
zero.
The fourth one also declares a as an integer and initializes
it to zero.
Note:
int a;
a = 0;
is different than
int a = 0;
The first case uses the assignment operator. The second case
uses the constructor.

If you throw constructors into it, then "int a(a);" and "int
a=0;" are different as well:). Still, the first is assignment,
and the second initialization, and there are cases, even with
int, where this makes a difference:

switch ( something )
{
case 0 :
int a = 0 ; // Illegal...
break ;

case 1:
int b ; // Legal...
b = 0 ;
break ;
}

(How's that for adding to the confusion:)?)
 
M

Mike Wahler

Hi,

I'm wondering if the following three statements are the same
No.

or only
the last two are the same?
No.


int a;

Defines a type 'int' object, which has an indeterminate
value if at block scope, or has a value of zero if at
file scope.

Declares a function named 'a', which has no arguments
and returns type 'int'.

Defines a type 'int' object, and initializes its value to zero.
Another form is:

int a(0);


-Mike
 
K

Kira Yamato

switch ( something )
{
case 0 :
int a = 0 ; // Illegal...
break ;

case 1:
int b ; // Legal...
b = 0 ;
break ;
}

(How's that for adding to the confusion:)?)

This is so weird. Is there a reason for initiations in switch
statements to be illegal?

However, I noticed that if you put braces around the case blocks, then
it compiles fine under g++ 4.0.1.

Some other weird observations below.

The following is legal (under g++ 4.0.1).
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // ok too!
break;
}

The following is illegal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // illegal here!
break;
case 2:
int c; // ok
c = 1;
break;
}

The following is legal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b; // ok
break;
case 2:
int c = 1; // ok
c = 1;
break;
}

It seems like the rule is that you cannot initialize a variable in a
declaration in a case block that is followed by another case block.
 
J

Joel Yliluoma

This is so weird. Is there a reason for initiations in switch
statements to be illegal?

A label (including the case labels) must be followed by a statement.

Apparently, this compiler does not believe
that "int a = 0;" is a statement but that "int b;" is.
 
I

Ioannis Gyftos

A label (including the case labels) must be followed by a statement.
Apparently, this compiler does not believe
that "int a = 0;" is a statement but that "int b;" is.

I thought that "int b;" is a statement in C++ contrary to C, such that
it allows you to declare variables anywhere inside a function etc. And
as I see it, it doesn't explain Kira's examples either.

(I blame James Kanze for confusing me - but it must have to do
something with assignment versus initialization)
 
A

Alf P. Steinbach

* Kira Yamato:
This is so weird. Is there a reason for initiations in switch
statements to be illegal?

However, I noticed that if you put braces around the case blocks, then
it compiles fine under g++ 4.0.1.

Some other weird observations below.

The following is legal (under g++ 4.0.1).
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // ok too!
break;
}

The following is illegal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // illegal here!
break;
case 2:
int c; // ok
c = 1;
break;
}

The following is legal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b; // ok
break;
case 2:
int c = 1; // ok
c = 1;
break;
}

It seems like the rule is that you cannot initialize a variable in a
declaration in a case block that is followed by another case block.

It's a bit more general.

You can't allow a jump from a place where a variable is not in scope, to
a place where that variable is in scope with a declaration that has an
initializer (and/or has non-POD type). The point is that an
initialization in C++ is meant to guarantee initialization. But of
course it doesn't, this language is too hairy, as T x = x exemplifies.

For more details see §6.7/3.

Cheers, & hth.,

- Alf
 
R

Ron Natalie

Joel said:
A label (including the case labels) must be followed by a statement.

Apparently, this compiler does not believe
that "int a = 0;" is a statement but that "int b;" is.

NO the issue is not that but the fact that it is not allowed
to JUMP over an initalization into the scope of a variable:

switch(i) {
case 0:
int j = 5;
break;
case 1:
// j is still in scope here, but if we jump
// to the case 1 label, we miss it's initialization
j++;
};

The fix is to put extra braces in:
switch(i) {
case 0: {
int j = 5;
break;
}
case 1:
// OK, no variable initialization bypassed.
 
J

James Kanze

This is so weird. Is there a reason for initiations in switch
statements to be illegal?

It's the result of a more general rule: you're not allowed to
jump around a non-trivial initialization: either an explicit
initialization or a definition with a type which has a
non-trivial constructor. Thus, for example, something like:

goto foo ;
std::ifstream in( "filename" ) ;
foo:
int i ;
in >> i ;

is illegal. In this case, it's also quite obvious that it
should be: you're attempting to use "in" without having invoked
its constructor, which can only cause problems. And of course:

goto foo ;
int i = 43 ;
foo :
std::cout << i ;

suffers from the same problem; you're attempting to use an
uninitialized i.

The apparently strange behavior in my example with switch is due
to this rule interacting with other particularities of the
language: the fact that the semantics of switch are exactly
those of goto, for example (think of what happens if you leave
out a break), and the fact that something like:

switch ( something ) {
int a ;
case 0 :
a = 1 ;
// ...
break ;

case 2:
a = 2 ;
// ...
break ;
}

is legal C, and the authors probably didn't want to break it in
C++.

The final result is that in almost every case, you should wrap
the actions in each case in {...}.
However, I noticed that if you put braces around the case
blocks, then it compiles fine under g++ 4.0.1.

Yes, because you don't jump around the initialization; the
variable isn't visible in the other cases.
Some other weird observations below.
The following is legal (under g++ 4.0.1).
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // ok too!
break;
}

Correct. What makes the code illegal is the presence of a case
after the the definition.
The following is illegal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // illegal here!
break;
case 2:
int c; // ok
c = 1;
break;

}
The following is legal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b; // ok
break;
case 2:
int c = 1; // ok
c = 1;
break;
}
It seems like the rule is that you cannot initialize a
variable in a declaration in a case block that is followed by
another case block.

That's the general idea. To put it more exactly, there is no
such thing as a "case block", and case labels are considered as
a target of a goto. The "block" is thus that of the switch, and
the rule is that you're not allowed a goto over a definition
with a non-trivial initialization to a point where the variable
being defined is still legal.

In practice, in all but the most trivial cases (every case
consists of just a single assignment or return), you should
probably systematically wrap all cases in a block, e.g.:

switch ( something )
{
case 0 :
{
// ...
}
break ;

case 1 :
{
// ...
}
break ;
}

etc.
 
J

James Kanze

Which is, of course, ridiculous. Both are statements.
I thought that "int b;" is a statement in C++ contrary to C,
such that it allows you to declare variables anywhere inside a
function etc.

It is a statement both in C and in C++. And modern C also
allows declaring variables in pretty much all of the places C++
does.
And as I see it, it doesn't explain Kira's examples either.
(I blame James Kanze for confusing me - but it must have to do
something with assignment versus initialization)

The assignment is actually irrelevant: it's a definition with
initialization vs. one without. C++ doesn't allow jumping over
or around initialization, and the semantics of switch are the
same as those of goto.
 
A

Alf P. Steinbach

* James Kanze:
It's the result of a more general rule: you're not allowed to
jump around a non-trivial initialization: either an explicit
initialization or a definition with a type which has a
non-trivial constructor.

You mean non-POD type: the standard defines this in terms of POD'ness.

Cheers,

- Alf
 
K

Kira Yamato

It's the result of a more general rule: you're not allowed to
jump around a non-trivial initialization: either an explicit
initialization or a definition with a type which has a
non-trivial constructor. Thus, for example, something like:

goto foo ;
std::ifstream in( "filename" ) ;
foo:
int i ;
in >> i ;

is illegal. In this case, it's also quite obvious that it
should be: you're attempting to use "in" without having invoked
its constructor, which can only cause problems. And of course:

goto foo ;
int i = 43 ;
foo :
std::cout << i ;

suffers from the same problem; you're attempting to use an
uninitialized i.

The apparently strange behavior in my example with switch is due
to this rule interacting with other particularities of the
language: the fact that the semantics of switch are exactly
those of goto, for example (think of what happens if you leave
out a break), and the fact that something like:

switch ( something ) {
int a ;
case 0 :
a = 1 ;
// ...
break ;

case 2:
a = 2 ;
// ...
break ;
}

is legal C, and the authors probably didn't want to break it in
C++.

The final result is that in almost every case, you should wrap
the actions in each case in {...}.


Yes, because you don't jump around the initialization; the
variable isn't visible in the other cases.



Correct. What makes the code illegal is the presence of a case
after the the definition.




That's the general idea. To put it more exactly, there is no
such thing as a "case block", and case labels are considered as
a target of a goto. The "block" is thus that of the switch, and
the rule is that you're not allowed a goto over a definition
with a non-trivial initialization to a point where the variable
being defined is still legal.

In practice, in all but the most trivial cases (every case
consists of just a single assignment or return), you should
probably systematically wrap all cases in a block, e.g.:

switch ( something )
{
case 0 :
{
// ...
}
break ;

case 1 :
{
// ...
}
break ;
}

etc.

Thanks for the detail explanation.
 
J

James Kanze

* James Kanze:
You mean non-POD type: the standard defines this in terms of
POD'ness.

So I see. I wonder if this was added to the standard, or if it
is just my memory playing tricks. (I haven't had the occasion
to actually look at this passage since the ARM. Many years ago.)
 
P

PengYu.UT

You missed one
int a(0);

The three you show do different things.

The first one declares a as an interger which is unitialized. Can contain
any value. Be careful, some compilers will initialize variables to 0 in
debug mode but not release mode sometimes causing hard to find errors.

The second one declares a function called a accepting no parameters and
retuning an integer.

The third one declares a as in integer and initializes it to zero.

The fourth one also declares a as an integer and initializes it to zero.

Note:
int a;
a = 0;

is different than
int a = 0;

The first case uses the assignment operator. The second case uses the
constructor.

My question was actually raised when I want to define a variable of
type T in a template function and I want that variable be initialized
to zero.

For example, let us say the template argument is T, which could be any
numerical classes or basic types, such as, int, double, complex, or
user defined numerical type from third party library, e.g. bigint.

Which one shall I use?

T a = 0;
T a = T();
T a;

Or cause, all classes has a default constructor, then T a; would be OK
(suppose all the default constructor would initialize it to zero). But
this is not good for basic types
..
T a =0; would be good for basic types, but the classes from a third
party library might not have an constructor like that.

T a; a = 0; has the same problem. The class might not have an
assignment operator.

In order to make T good for as many situations as possible, what is
the common practice?

Thanks,
Peng
 
A

Alf P. Steinbach

* James Kanze:
So I see. I wonder if this was added to the standard, or if it
is just my memory playing tricks. (I haven't had the occasion
to actually look at this passage since the ARM. Many years ago.)

Well, the ARM says, in §6.7, "It is illegal to jump past a declaration
with an explicit or implicit initializer unless the declaration is in an
inner block that is not entered (that is, completely bypassed by the
transfer of control) or unless the jump is from a point where the
variable has already been initialized."

The commentary relates the requirement also to destructor calls.

"explicit or implicit initializer" seems to be essentially the same as POD?


Cheers, & hth.,

- Alf
 
V

Victor Bazarov

My question was actually raised when I want to define a variable of
type T in a template function and I want that variable be initialized
to zero.

For example, let us say the template argument is T, which could be any
numerical classes or basic types, such as, int, double, complex, or
user defined numerical type from third party library, e.g. bigint.

Which one shall I use?

T a = 0;
T a = T();
T a;

Or cause, all classes has a default constructor, then T a; would be OK
^^^^^^^^
"Of course"?

You probably should use "_if_ the class has the default c-tor, then T a;
would be OK".
(suppose all the default constructor would initialize it to zero). But
this is not good for basic types
Correct.

.
T a =0; would be good for basic types, but the classes from a third
party library might not have an constructor like that.

That would require a constructor that takes an integral value or
a pointer and an accessible copy-constructor. Usually they are there,
but sometimes they aren't.
T a; a = 0; has the same problem. The class might not have an
assignment operator.
Right.

In order to make T good for as many situations as possible, what is
the common practice?

The common practice is to require something. In the case

T a = T();

a default c-tor (for classes) and accessible copy c-tor are required.
The built-in types work very well in this case.

Here is a possible scheme that should do the same thing, essentially.

static T zeroT; // will be zero-initialised before anything else
// so it should be OK even for built-in types
T a(zeroT); // needs a copy-ctor

....

V
 
P

PengYu.UT

^^^^^^^^
"Of course"?

You probably should use "_if_ the class has the default c-tor, then T a;
would be OK".

I actually meant that. I just forgot to put "if" there.
That would require a constructor that takes an integral value or
a pointer and an accessible copy-constructor. Usually they are there,
but sometimes they aren't.


The common practice is to require something. In the case

T a = T();

a default c-tor (for classes) and accessible copy c-tor are required.
The built-in types work very well in this case.

Here is a possible scheme that should do the same thing, essentially.

static T zeroT; // will be zero-initialised before anything else
// so it should be OK even for built-in types
T a(zeroT); // needs a copy-ctor

Thank you for your answer.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top