Unexpected behaviour

I

Ioannis Vranos

For the code


#include <iostream>

class Blah
{
int i;

public:

Blah(const Blah &obj)
{
std::cout<<"Copy Constructor called!\n";
i=obj.i;
}

Blah()
{
std::cout<<"Default Constructor called!\n"; i=0;
}
};


int main()
{
Blah poo1(Blah());

Blah poo2=Blah();
}


I only get

C:\c>temp
Default Constructor called!

C:\c>


which is produced for the second object while nothing is produced for
the first.


Why no message is produced for the first, and why only a default
constructor message is produced for the second?



I expected:

C:\c>temp
Default Constructor called!
Copy Constructor called!
Default Constructor called!
Copy Constructor called!

C:\c>
 
J

John Harrison

Ioannis Vranos said:
For the code


#include <iostream>

class Blah
{
int i;

public:

Blah(const Blah &obj)
{
std::cout<<"Copy Constructor called!\n";
i=obj.i;
}

Blah()
{
std::cout<<"Default Constructor called!\n"; i=0;
}
};


int main()
{
Blah poo1(Blah());

Blah poo2=Blah();
}


I only get

C:\c>temp
Default Constructor called!

C:\c>


which is produced for the second object while nothing is produced for
the first.


Why no message is produced for the first, and why only a default
constructor message is produced for the second?

Because this

Blah poo1(Blah());

is a function prototype. You can check this by adding the function call at
the end of main.

poo1(0);

Have you been listening to JKop again?

john
 
V

Victor Bazarov

Ioannis said:
For the code


#include <iostream>

class Blah
{
int i;

public:

Blah(const Blah &obj)
{
std::cout<<"Copy Constructor called!\n";
i=obj.i;
}

Blah()
{
std::cout<<"Default Constructor called!\n"; i=0;
}
};


int main()
{
Blah poo1(Blah());

Blah poo2=Blah();
}


I only get

C:\c>temp
Default Constructor called!

C:\c>


which is produced for the second object while nothing is produced for
the first.

The statement

Blah poo1(Blah());

is a _declaration_ of a function 'poo1'. Read the FAQ.
Why no message is produced for the first, and why only a default
constructor message is produced for the second?

Because 'poo1' is not an object.
I expected:

C:\c>temp
Default Constructor called!
Copy Constructor called!
Default Constructor called!
Copy Constructor called!

Too bad. Study the declaration syntax.

V
 
J

JKop

Because this
Blah poo1(Blah());

is a function prototype. You can check this by adding the function call
at the end of main.

poo1(0);

Have you been listening to JKop again?

john


Now that's embarassing...


-JKop
 
I

Ioannis Vranos

John said:
Have you been listening to JKop again?

Ehehehe, we have an expression here in Greece. When you are talking with
someone telling wrong things, confusion comes out and you say "I will
forget even what I know".

That is what happened here, I got confused.


That said, his intention was good. :)


BTW in the expression Blah poo=Blah() why not the copy constructor nor
the default constructor are called?
 
I

Ioannis Vranos

Fixed:


BTW in the expression Blah poo=Blah() why only the default constructor
is called?
 
V

Victor Bazarov

Ioannis said:
Fixed:


BTW in the expression Blah poo=Blah() why only the default constructor
is called?

Because it is allowed to be optimized to do so.

V
 
I

Ioannis Vranos

Victor said:
Because it is allowed to be optimized to do so.



However consider this:


#include <iostream>

struct Blah
{
public:

int i;

Blah(const Blah &obj)
{
std::cout<<"Copy Constructor called!\n";

i=10*obj.i;
}

Blah()
{
std::cout<<"Default Constructor called!\n";

i=1;
}

Blah &operator=(const Blah &obj)
{
std::cout<<"Assignment used!\n";

i=5*obj.i;

return *this;
}

};


int main()
{
Blah poo=Blah();

std::cout<<poo.i<<std::endl;
}



C:\c>temp
Default Constructor called!
1

C:\c>



Any explanation?
 
I

Ioannis Vranos

So in summary we have got:


T x = T():

For POD types it is equivalent to initialisation to 0 for built in types
and all members to 0 for structs.

[Addition of 2003]: For non-POD types without a default constructor
definition, also all members to 0.


-----------------------------------------------------------------------


For non-POD types with a default constructor definition, it is
equivalent to T x; - no temporary is created and copy constructor is not
called.
 
I

Ioannis Vranos

Ioannis said:
So in summary we have got:


T x = T():

For POD types it is equivalent to initialisation to 0 for built in types
and all members to 0 for structs.

[Addition of 2003]: For non-POD types without a default constructor
definition, also all
POD

members to 0.


-----------------------------------------------------------------------


For non-POD types with a default constructor definition, it is
equivalent to T x; - no temporary is created and copy constructor is not
called.
 
R

Rolf Magnus

Ioannis said:
However consider this:


#include <iostream>

struct Blah
{
public:

int i;

Blah(const Blah &obj)
{
std::cout<<"Copy Constructor called!\n";

i=10*obj.i;
}

Blah()
{
std::cout<<"Default Constructor called!\n";

i=1;
}

Blah &operator=(const Blah &obj)
{
std::cout<<"Assignment used!\n";

i=5*obj.i;

return *this;
}

};


int main()
{
Blah poo=Blah();

std::cout<<poo.i<<std::endl;
}



C:\c>temp
Default Constructor called!
1

C:\c>



Any explanation?

Same as before. This is allwed as an optimization.
 
I

Ioannis Vranos

More "legally" accurate:


So in summary we have got:


T x = T():

For POD types it is equivalent to initialisation to 0 for built in types
and all members to 0 for structs.


[Addition of 2003]: For non-POD types without a default constructor
definition, also all POD members to 0.
 
M

Mikhail N. Kupchik

Ioannis Vranos said:
int main()
{
Blah poo1(Blah());
This is not a definition of object `poo1'. This is a declaration of
function poo1 that takes returns Blah and takes argument of type "Blah
(*)()" - a pointer to function that takes no arguments and returns
object of type Blah.
Blah poo2=Blah();
}

-- Mikhail Kupchik
 
R

Ron Natalie

Ioannis Vranos said:
So in summary we have got:


T x = T():

For POD types it is equivalent to initialisation to 0 for built in types
and all members to 0 for structs.

Not ture. In 1999-speak it's default initialization for all types. If T is POD
types this means zero initialization. If T is not POD, then what ever default
initailization means for that type.
[Addition of 2003]: For non-POD types without a default constructor
definition, also all members to 0.

Addition of 2003, change the working to "value initialization" which is still
zero initialized for POD's, but for classes with no user defined constructor,
it means value-initialize each member separately.
 
I

Ioannis Vranos

Ron said:
Not ture. In 1999-speak


I assume you mean 1998.


it's default initialization for all types. If T is POD
types this means zero initialization. If T is not POD, then what ever default
initailization means for that type.
[Addition of 2003]: For non-POD types without a default constructor
definition, also all members to 0.


Addition of 2003, change the working to "value initialization" which is still
zero initialized for POD's, but for classes with no user defined constructor,
it means value-initialize each member separately.


OK. As far as I can understand what I said do not contradict with yours,
right?
 
O

Old Wolf

Ioannis Vranos said:
#include <iostream>

class Blah
{
public:
Blah(const Blah &obj) {
std::cout<<"Copy Constructor called!\n";
}
Blah() {
std::cout<<"Default Constructor called!\n";
}
};

int main()
{
Blah poo1(Blah());
Blah poo2=Blah();
}

What's with everybody calling their objects 'poo'.
I only get

Default Constructor called!

I expected:

Default Constructor called!
Copy Constructor called!
Default Constructor called!
Copy Constructor called!

Case 1 declares a function 'poo1' returning Blah and taking
as parameter, a pointer to function taking no parameters and
returning Blah. So no output is generated.

In case 2, the compiler optimises out the copy construction.
This is permitted in some circumstances (eg. this one, and
in RVO). So you only get the message for the default construction.
 
Z

Zian Smith

Ioannis Vranos said:
For the code

int main()
{
Blah poo1(Blah());

This is subtle. you are not actually creating a new object called poo1
here. You are instead declaring a function called poo1 that takes a
single parameter, and returns an object of type Blah. The single
parameter that poo1 takes is a pointer to a some function that takes a
void parameter and returns an object of type Blah.

Blah poo2=Blah();

I'm not sure about this one. You are creating a new object called
poo2, and creating a temporary object via Blah(). A constructor has to
be called for poo2 and I would have expected the copy constructor to
be called. However the default constructor is indeed being called.
My *GUESS* is that since Blah() generates a temporary object anyways,
instead of calling the default constructor for the temporary object
and then the copy constructor for the poo2 object, optimization is
done, and a single default constructor call for poo2 is made instead.

However, consider the following: If you overload the + operator for
the Blah class (so if you "add" two blah objects you get another Blah
object), the following will call the copy constructor even though the
+ operator generates a temporary object:

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



-Z.Smith
 
R

Rolf Magnus

Zian said:
This is subtle. you are not actually creating a new object called poo1
here. You are instead declaring a function called poo1 that takes a
single parameter, and returns an object of type Blah. The single
parameter that poo1 takes is a pointer to a some function that takes a
void parameter and returns an object of type Blah.

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'm not sure about this one. You are creating a new object called
poo2, and creating a temporary object via Blah(). A constructor has to
be called for poo2 and I would have expected the copy constructor to
be called. However the default constructor is indeed being called.
My *GUESS* is that since Blah() generates a temporary object anyways,
instead of calling the default constructor for the temporary object
and then the copy constructor for the poo2 object, optimization is
done, and a single default constructor call for poo2 is made instead.

Yes. That's how it works.
However, consider the following: If you overload the + operator for
the Blah class (so if you "add" two blah objects you get another Blah
object), the following will call the copy constructor even though the
+ operator generates a temporary object:

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

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.
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top