Unexpected behaviour

I

Ioannis Vranos

Rolf said:
This rule looks really stupid to me, and I see many newbies being confused
by this. Why didn't they just leave it like C and require the keyword void
to denote an empty parameter list? Then:

Blah poo1(Blah());

would just be a default initialization, like one would expect on the first
sight. If you want instead the function declaration, you would need to
write:

Blah poo1(Blah(void));

Why wasn't it done that way in C++? All those subtle "this isn't an object
definition - it's a function declaration" problems wouldn't ever have
existed.


Actually a function declaration with empty parenthesis is also a valid C
declaration with a different meaning. Consider the C code:


void f();


int main()
{
float x=4;

f(x);

return 0;
}


void f(char *p)
{
}



Ioannis Vranos

http://www23.brinkster.com/noicys
 
G

Greg Comeau

This rule looks really stupid to me, and I see many newbies being confused
by this. Why didn't they just leave it like C and require the keyword void
to denote an empty parameter list? Then:

Blah poo1(Blah());

would just be a default initialization, like one would expect on the first
sight. If you want instead the function declaration, you would need to
write:

Blah poo1(Blah(void));

Why wasn't it done that way in C++? All those subtle "this isn't an object
definition - it's a function declaration" problems wouldn't ever have
existed.

If I understand what you just said, you have what C does wrong.
That is, the above is a function declaration in C too, and void
is not required.
 
N

Nicolas Pavlidis

Victor Bazarov said:
The statement

Blah poo1(Blah());

is a _declaration_ of a function 'poo1'. Read the FAQ.

Can you tell me why the part Blah() inside the statement doesn't
invoke the compiler (or linker) to say anything. The hole statement is a
function declaration, that's clear, but what's about the Blah() call
inside?

Kind regards,
Nicolas
 
J

JKop

Nicolas Pavlidis posted:
Can you tell me why the part Blah() inside the statement doesn't
invoke the compiler (or linker) to say anything. The hole statement is a
function declaration, that's clear, but what's about the Blah() call
inside?

Kind regards,
Nicolas

That's the stick part!

It thinks that it's

Blah poo(Blah);

It discards the parenthesis. Just as how you can write:

(5+6)

instead of:

5+6


-JKop
 
J

JKop

Blah x,y;
Blah z = x + y; //calls copy constructor for z
Blah z = Blah() + Blah() //will also call the copy constructor

Correct.

And also for more clarity:

Blah z;

z = x + y; //calls assignment
z = Blah() + Blah() //calss assignment


-JKop
 
N

Nicolas Pavlidis

[...]
That's the stick part!

It thinks that it's

Blah poo(Blah);

It discards the parenthesis. Just as how you can write:

Oh, ok.
Thanks!

Kind regrads,
Nicolas
 
J

JKop

Nicolas Pavlidis posted:
[...]
That's the stick part!

It thinks that it's

Blah poo(Blah);

It discards the parenthesis. Just as how you can write:

Oh, ok.
Thanks!

Kind regrads,
Nicolas

Sorry, I think I may be mistaken there...

Even more disgustingly, I don't think the argument is of
type:

Blah

but of type:

void (*Blah)()


ie: it takes a function pointer


I'm not sure about this though. I might try it out...


-JKop
 
R

Rolf Magnus

Ioannis said:
Actually a function declaration with empty parenthesis is also a valid C
declaration with a different meaning.

I know. However, one could simply have left that one out in C++. Would still
be closer to C than the current way.
 
R

Rolf Magnus

Greg said:
If I understand what you just said, you have what C does wrong.

No, I don't.
That is, the above is a function declaration in C too, and void
is not required.

void is required to make the compiler know that the parameter list is empty.
If you leave it out, it means the parameter list is not yet specified and
may not be empty, but I guess you know that.
Now in C++, a void parameter list has the same meaning as in C, but leaving
out the void means something different than in C. What I say is that they
should have forbidden that one so that you always have to explicitly make
it void. I see now that this is actually not closer to C, but I still think
that would be a good idea. However, I guess it can't be changed anymore in
a later version of the standard since that would make almost all the
existing C++ code invalid.
 
G

Greg Comeau

Can you tell me why the part Blah() inside the statement doesn't
invoke the compiler (or linker) to say anything. The hole statement is a
function declaration, that's clear, but what's about the Blah() call
inside?

The Blah() inside is not a call. It's the declaration of a function.
When we see:

int foo();

many will say that the type is int(*)(), afterall this works:

int (*p)() = foo;

however, that's what the type of foo is _converted into_.
The actuall type of foo is: int(). So the type of this:

char bar(float);

is char(float). Even looking at these is unconfortable'ish.
But Blah() is exactly that. If we take int() and say T is int,
that gives T() where T is int. Well, if T is Blah, we
get Blah(). So poo1 return a Blah, and accept as an
argument an Blah(), which is a function returning a Blah
and unspecified what it accepts in C, and no args in C++.

As with an argument of array's:

void arr(int a[99]);

you don't actually pass whole arrays, so the [99] is only
of syntactic nature, since it's converted to a pointer,
you can't pass a whole array like that, well, you can't
pass a function either, and it too will be converted to
a pointer to a function instead.
 
G

Greg Comeau

Nicolas Pavlidis posted:

Sorry, I think I may be mistaken there...

Even more disgustingly, I don't think the argument is of
type:

Blah

but of type:

void (*Blah)()


ie: it takes a function pointer


I'm not sure about this though. I might try it out...

Good idea. Always a good idea :)
 
G

Greg Comeau

No, I don't.


void is required to make the compiler know that the parameter list is empty.
If you leave it out, it means the parameter list is not yet specified and
may not be empty, but I guess you know that.

My point is that in C even w/o the void, the thing is still a declaration,
though I agree not a declaration of the same thing.
Now in C++, a void parameter list has the same meaning as in C, but leaving
out the void means something different than in C.
Agreed.

What I say is that they
should have forbidden that one so that you always have to explicitly make
it void.

I can understand "should have" but took your original "leave it like C
and require the keyword void" to mean something else than you've
just said, since C does not require it, just that it means something else.
I see now that this is actually not closer to C, but I still think
that would be a good idea. However, I guess it can't be changed anymore in
a later version of the standard since that would make almost all the
existing C++ code invalid.

Let's agree that both could use various syntax overhauls :)
perhaps avoiding void altogeher.
 
Z

Zian Smith

This rule looks really stupid to me, and I see many newbies being confused
by this. Why didn't they just leave it like C and require the keyword void
to denote an empty parameter list? Then:

Blah poo1(Blah());

would just be a default initialization, like one would expect on the first
sight. If you want instead the function declaration, you would need to
write:

Blah poo1(Blah(void));

Why wasn't it done that way in C++? All those subtle "this isn't an object
definition - it's a function declaration" problems wouldn't ever have
existed.

I have to agree with you here. This was something that had me
scratching my head for a while as well when I was a newbie :)
That depends. Still some compilers won't call the copy constructor. The
operator+ can directly construct its return value into z, using what is
usually referred to as return value optimization. Basically, the calling
function (where z is defined) just reserves the space and gives the address
of it as a hidden parameter to the function (or operator in this case),
which then can directly construct its return value into that address, so
that no copy is needed.

So are you saying that when a new object is being created, whether a
default/overloaded constructor is called or a copy constructor is
called is compiler dependent? That seems a little perplexing..
Suppose I want to keep count of how many new objects are being
created, and how many times a copy is made. So just having counters in
the default/overloaded/copy constuctors is not reliable enough?

-Z.Smith
 
I

Ioannis Vranos

Zian said:
So are you saying that when a new object is being created, whether a
default/overloaded constructor is called or a copy constructor is
called is compiler dependent? That seems a little perplexing..
Suppose I want to keep count of how many new objects are being
created, and how many times a copy is made. So just having counters in
the default/overloaded/copy constuctors is not reliable enough?


No, upon initialisation with other objects, the copy constructor is
always called.
 
V

Victor Bazarov

Zian said:
[...]
So are you saying that when a new object is being created, whether a
default/overloaded constructor is called or a copy constructor is
called is compiler dependent?

Yes. It's called "optimisation". Compilers are allowed to do that.
That seems a little perplexing..
Suppose I want to keep count of how many new objects are being
created, and how many times a copy is made. So just having counters in
the default/overloaded/copy constuctors is not reliable enough?

Why not? If you want to count how many objects _really_ are created,
that should be sufficient. If you want to know what the _semantics_
of creation/initialisation are, you cannot use your compiler as the
tool to supply you with that information simply because it has leeway
to optimise some copying away. For semantics, study the Standard.

V
 
R

Rolf Magnus

Zian said:
So are you saying that when a new object is being created, whether a
default/overloaded constructor is called or a copy constructor is
called is compiler dependent?

Well, that's not the full story. See below.
That seems a little perplexing..
Suppose I want to keep count of how many new objects are being
created, and how many times a copy is made. So just having counters in
the default/overloaded/copy constuctors is not reliable enough?

Yes, it is reliable. The idea is that under certain circumstances, if you
create a temporary and then copy-construct a variable from it, the compiler
is allowed to eliminate that temporary (and thus its construction and - for
that matter - its destruction) and instead directly construct the variable.
So your counter will still work. The copy constructor is simply not called
because no copy is made. Remember, each object gets constructed exactly
once and destoyed exactly once.
Consider this:

struct Foo
{
Foo(const Foo&);
Foo(int);

int data;
};

Foo operator+(const Foo& lhs, const Foo& rhs)
{
return Foo(lhs.data + rhs.data);
}

int main()
{
Foo a = 3;
Foo b = 5;
Foo f = a + b;
}

Without return value optimization, the compiler would need two calls to the
copy constructor. First operator+ creates a temporary Foo that gets copied
on returning. Then, f is copy constructed from that return value.
Now the compiler is allowed to elide one or both of those copies and let
operator+ directly construct f as a shortcut. Basically, this is done by
main just providing the address of f (before it actually is constructed) to
operator+ as a hidden parameter. Then operator+ doesn't use its own local
memory for the temporary Foo, but instead uses the address of f to
construct 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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top