Testing my knowledge: how many constructors are called

A

AhmedB

Hi,

I wrote this program, compiled it and ran it with the expectation that
I will get two printed lines (one from each ctor):

#include <cstdio>
class A
{
public:
A(int a)
{
fprintf(stderr, "A(int a)\n");
i = a;
}
A(const A& a)
{
fprintf(stderr, "A(const A& a)\n");
i = a.i;
}
private:
int i;
private:
const A& operator= (const A&)
{
}
};

int main()
{
A a = A(5);
return 0;
}

I only got:

A(int a)


So I thought Ok, maybe the compiler is compiling the

A a = A(5); to be

A a(5) somehow,

So I went ahead and changed the code to make the copy constructor
explicit, as follows:

#include <cstdio>
class A
{
public:
A(int a)
{
fprintf(stderr, "A(int a)\n");
i = a;
}
explicit A(const A& a)
{
fprintf(stderr, "A(const A& a)\n");
i = a.i;
}
private:
int i;
private:
const A& operator= (const A&)
{
}
};

int main()
{
A a = A(5);
return 0;
}

Then I tried compiling the code and got the following:

test.cc: In function ‘int main()’:
test.cc:42: error: no matching function for call to ‘A::A(A)’
test.cc:18: note: candidates are: A::A(int)

So my question is, if my understanding is correct and this is the
sequence that is going on:
1. An A::A(int) constructor is used to convert an int to an A,
followed by
2. An A::A(const A&) constructor is used to copy the temporary A
and this is why I'm getting the compilation error when I make the
A::A(const A&) explicit, then why am I not getting two printed lines
in the first case? Is there something else going on here that I'm not
paying attention to?

This code is compiled/run on a Suse 10.3 Linux box with gcc/g++
version 4.2.1.

Regards,
Ahmed
 
R

raicuandi

Hi,

I wrote this program, compiled it and ran it with the expectation that
I will get two printed lines (one from each ctor):

#include <cstdio>
class A
{
        public:
        A(int a)
        {
                fprintf(stderr, "A(int a)\n");
                i = a;
        }
        A(const A& a)
        {
                fprintf(stderr, "A(const A& a)\n");
                i = a.i;
        }
        private:
        int i;
        private:
        const A& operator= (const A&)
        {
        }

};

int main()
{
        A a = A(5);
        return 0;

}

I only got:

A(int a)

So I thought Ok, maybe the compiler is compiling the

A a = A(5); to be

A a(5) somehow,

So I went ahead and changed the code to make the copy constructor
explicit, as follows:

#include <cstdio>
class A
{
        public:
        A(int a)
        {
                fprintf(stderr, "A(int a)\n");
                i = a;
        }
        explicit A(const A& a)
        {
                fprintf(stderr, "A(const A& a)\n");
                i = a.i;
        }
        private:
        int i;
        private:
        const A& operator= (const A&)
        {
        }

};

int main()
{
        A a = A(5);
        return 0;

}

Then I tried compiling the code and got the following:

test.cc: In function ‘int main()’:
test.cc:42: error: no matching function for call to ‘A::A(A)’
test.cc:18: note: candidates are: A::A(int)

So my question is, if my understanding is correct and this is the
sequence that is going on:
1. An A::A(int) constructor is used to convert an int to an A,
followed by
2. An A::A(const A&) constructor is used to copy the temporary A
and this is why I'm getting the compilation error when I make the
A::A(const A&) explicit, then why am I not getting two printed lines
in the first case? Is there something else going on here that I'm not
paying attention to?

This code is compiled/run on a Suse 10.3 Linux box with gcc/g++
version 4.2.1.

Regards,
Ahmed

This has got to be the most pointless exercise I've seen this week. :)
Why would anyone *want* an extra copy-constructor?..
 
A

AhmedB

 AhmedB said:
I wrote this program, compiled it and ran it with the expectation that
I will get two printed lines (one from each ctor):
[snipped class A with ctors A( int ) and A( A const& )]
int main()
{
   A a = A(5);
   return 0;
}
I only got:
So I thought Ok, maybe the compiler is compiling the
A a = A(5); to be
A a(5) somehow,

Right, the compiler is allowed to optimize out the temporary and copy
ctor call.
So I went ahead and changed the code to make the copy constructor
explicit, as follows:
[snip code]
Then I tried compiling the code and got the following:
test.cc: In function Œint main()¹:
test.cc:42: error: no matching function for call to ŒA::A(A)¹
test.cc:18: note: candidates are: A::A(int)

The above optimization must not change the semantics. This way, the
(in)correctness of the code is not affected by this optimization.

Thanks that makes perfect sense, the compiler is optimizing it in one
path, and sort of un-optimizing it (or more like leaving its semantics
alone) in the other case, I've even tried using a g++ -O0 before
posting it, it didn't seem to make a difference either. Thanks for the
clarification

Regards,
Ahmed
 
A

AhmedB

This has got to be the most pointless exercise I've seen this week. :)
Why would anyone *want* an extra copy-constructor?..

Not a matter of *want* but sometimes one wants to check their
knowledge and understanding with a simple example, and boom they get
surprised due to the compiler doing some optimization. I'm one of
those who are interested in _understanding_ how/why things work/don't
work, rather than taking things for granted and settling for 'that's
the way it works' type of thought.
 
E

Erik Wikström

This has got to be the most pointless exercise I've seen this week. :)
Why would anyone *want* an extra copy-constructor?..

This has got to be the most pointless answer I've seen this week. :)
Why would anyone *want* to write it?

Seriously though, if you do not know that the compiler is allowed some
optimisations which will change the semantics of the language (from what
one might expect) it is possible to get some nasty surprises.
 
J

Juha Nieminen

blargg said:
Right, the compiler is allowed to optimize out the temporary and copy
ctor call.

Note that, AFAIK, if the compiler obeys the standard, it will require
for the copy constructor to be accessible (ie. not private) even if it
never calls it.
 
A

AhmedB

The optimization doesn't change the semantics of the language. If the
copy constructor has side effects the optimization changes the
semantics of the program.

Agreed, and I went back, made the two constructors non-equivalent in
their side effects (setting i) just to test how intelligent the
compiler is in its optimization and sure enough it's still calling the
A::A(int) and so in this case the optimization vs. the non-
optimization will yield different results and nasty surprises if one
is not cautious and aware of what's actually going on.

-Ahmed
 

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,007
Latest member
obedient dusk

Latest Threads

Top