Visual C++ 2003 EE is used.

The program that follows

#include "stdafx.h"

#include <iostream>
#pragma hdrstop
#include <conio.h>

class A {};
class B
{
public:
B() { std::cout << "Inside B()" << std::endl; b = 0; }
B( const A & ) { std::cout << "Inside B( const A & )" << std::endl; b =
1; }
B( const B & ) { std::cout << "Inside B( const B & )" << std::endl; b =
2; }
int get_b() const { return b; }
private:
int b;
};

int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b1( a );
std::cout << "b1.b = " << b1.get_b() << std::endl;
B b2 = a;
std::cout << "b2.b = " << b2.get_b() << std::endl;
B b3 = B( a );
std::cout << "b3.b = " << b3.get_b() << std::endl;

return EXIT_SUCCESS;
}


gives the result

Inside B( const A & )
b1.b = 1
Inside B( const A & )
b2.b = 1
Inside B( const A & )
b3.b = 1
Press any key to continue . . .



Is it a bug that b3.b = 1? I guessed that b3.b must be equal to 2.

If the copy constructor will be declared as private then the error

error C2248: 'B::B' : cannot access private member declared in class 'B'

will be issued for the statement

B b3 = B( a );

O'k. However what constructor must be called for the statement B b2 = a; ?

If the keyword explicit will be placed before B( const A & ) the error

error C2440: 'initializing' : cannot convert from 'A' to 'B'

will be issued for the statement

B b2 = a;

Vladimir Grigoriev

Re: The C++ standard's rule for selecting a constructor by Vladimir

Vladimir
Wed Apr 16 06:36:21 CDT 2008


"Vladimir Grigoriev" <vlad.moscow@mail.ru> wrote in message
news:%23fU4jR7nIHA.1580@TK2MSFTNGP06.phx.gbl...
> Visual C++ 2003 EE is used.
>
> The program that follows
>
> #include "stdafx.h"
>
> #include <iostream>
> #pragma hdrstop
> #include <conio.h>

Sorry, don't take into account 'conio.h' and 'hdrstop'. They are from BCB.

Vladimir Grigoriev



Re: The C++ standard's rule for selecting a constructor by Cezary

Cezary
Wed Apr 16 06:55:00 CDT 2008

Hello,

Vladimir Grigoriev wrote:
> Is it a bug that b3.b = 1? I guessed that b3.b must be equal to 2.

No. It isn't a bug. 8.5[14] and 12.8[15] state that ,,an implementation
is allowed to omit the copy construction of a class object even if copy
constructor for the object has side effects'' (assigning 2 to b is the
side effect in your case).

> However what constructor must be called for the statement B b2 = a; ?

Conversion constructor ( B::B(const A&) ), and then copy constructor (
B::B(const B&) ). According to the rules mentioned above (8.5[14],
12.8[15]) calling of the second one (copy constructor) can be elised
(but both of them must be accessible).

-- best regards

Cezary Noweta

Re: The C++ standard's rule for selecting a constructor by Vladimir

Vladimir
Wed Apr 16 07:14:39 CDT 2008


"Cezary H. Noweta" <chncc@noemail.noemail> wrote in message
news:u9A2pi7nIHA.2632@TK2MSFTNGP04.phx.gbl...
> Hello,
>
> Vladimir Grigoriev wrote:
>> Is it a bug that b3.b = 1? I guessed that b3.b must be equal to 2.
>
> No. It isn't a bug. 8.5[14] and 12.8[15] state that ,,an implementation is
> allowed to omit the copy construction of a class object even if copy
> constructor for the object has side effects'' (assigning 2 to b is the
> side effect in your case).
>

And how big must be the 'side effects' that the compiler does not ignore
them? Is any rule?

>> However what constructor must be called for the statement B b2 = a; ?
>
> Conversion constructor ( B::B(const A&) ), and then copy constructor (
> B::B(const B&) ). According to the rules mentioned above (8.5[14],
> 12.8[15]) calling of the second one (copy constructor) can be elised (but
> both of them must be accessible).
>
> -- best regards
>
So the statements

B b( a ); and B b = a; are not equivalent?

Vladimir Grigoriec



Re: The C++ standard's rule for selecting a constructor by Igor

Igor
Wed Apr 16 07:25:39 CDT 2008

"Vladimir Grigoriev" <vlad.moscow@mail.ru> wrote in message
news:OEwSfr7nIHA.2636@TK2MSFTNGP04.phx.gbl
> "Cezary H. Noweta" <chncc@noemail.noemail> wrote in message
> news:u9A2pi7nIHA.2632@TK2MSFTNGP04.phx.gbl...
>> Vladimir Grigoriev wrote:
>>> Is it a bug that b3.b = 1? I guessed that b3.b must be equal to 2.
>>
>> No. It isn't a bug. 8.5[14] and 12.8[15] state that ,,an
>> implementation is allowed to omit the copy construction of a class
>> object even if copy constructor for the object has side effects''
>> (assigning 2 to b is the side effect in your case).
>>
> And how big must be the 'side effects' that the compiler does not
> ignore them? Is any rule?

The compiler may choose to elide the copy constructor no matter what
it's doing (in fact, without even knowing what it's doing, since its
implementation may be in a different source file).

> So the statements
>
> B b( a ); and B b = a; are not equivalent?

No, though often they compile down to the same code. The latter requires
an accessible copy constructor for B (even though it may not actually
call it), the former doesn't.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: The C++ standard's rule for selecting a constructor by Cezary

Cezary
Wed Apr 16 07:29:36 CDT 2008

Hello,

Vladimir Grigoriev wrote:
> And how big must be the 'side effects' that the compiler does not ignore
> them? Is any rule?

The sky is the limit ;) Call to the copy ctor may be eliged if it has
any side effects (or not at all).

> B b( a ); and B b = a; are not equivalent?

No they are different in that the first direct-initialization, and the
second is copy-initialization. In the first case, constructors of B are
considered, while in the second case, constructors of B and conversion
functions of A (similar to A::operator B(); ) are considered.
Additionally, in the second case copy constructor is invoked, but call
to it can be omitted, thus only access to the copy ctor is checked (i.e.
it must be accessible - must be public in your case).

To fulfil my previous post, when you make the copy ctor private, the
error C2248, should appear already at the ,,B b2 = a;''. It doean't
appear there due to a bug in the compiler.

-- best regards

Cezary Noweta

Re: The C++ standard's rule for selecting a constructor by Alex

Alex
Wed Apr 16 07:38:50 CDT 2008

"Vladimir Grigoriev" wrote:
>> No. It isn't a bug. 8.5[14] and 12.8[15] state that ,,an
>> implementation is allowed to omit the copy construction of a
>> class object even if copy constructor for the object has side
>> effects'' (assigning 2 to b is the side effect in your case).
>
> And how big must be the 'side effects' that the compiler does
> not ignore them? Is any rule?

The rule is that a call to the copy constructor may be legally
omitted. The size of the side effect is of no importance here.

> So the statements
>
> B b( a ); and B b = a; are not equivalent?

Yes, they aren't equivalent. See the "Compiler chooses conv ctor -
why?" thread in this group that started on 13 Apr 2008.


HTH
Alex



Re: The C++ standard's rule for selecting a constructor by Vladimir

Vladimir
Wed Apr 16 08:28:15 CDT 2008


"Igor Tandetnik" <itandetnik@mvps.org> wrote in message
news:Of7T9z7nIHA.3804@TK2MSFTNGP02.phx.gbl...
> "Vladimir Grigoriev" <vlad.moscow@mail.ru> wrote in message
> news:OEwSfr7nIHA.2636@TK2MSFTNGP04.phx.gbl
>> "Cezary H. Noweta" <chncc@noemail.noemail> wrote in message
>> news:u9A2pi7nIHA.2632@TK2MSFTNGP04.phx.gbl...
>>> Vladimir Grigoriev wrote:
>>>> Is it a bug that b3.b = 1? I guessed that b3.b must be equal to 2.
>>>
>>> No. It isn't a bug. 8.5[14] and 12.8[15] state that ,,an
>>> implementation is allowed to omit the copy construction of a class
>>> object even if copy constructor for the object has side effects''
>>> (assigning 2 to b is the side effect in your case).
>>>
>> And how big must be the 'side effects' that the compiler does not
>> ignore them? Is any rule?
>
> The compiler may choose to elide the copy constructor no matter what it's
> doing (in fact, without even knowing what it's doing, since its
> implementation may be in a different source file).

It is awful is not it?
So the statements is not equivalent

B b1( a );
B b2 = b1;

and

B b2 = B( a );

I think it is a big gap in the standard which in essence is a source of hard
found errors. According to the logic we have that

T x = value;
T y = x;

and

T z = value;

will give the result of z != y.

I.e. general speaking we should not trust that for

int x = 2; int y = x; int z = 2;
we will get z == y.
It makes programmer life harder!

Vladimir Grigoriev




Re: The C++ standard's rule for selecting a constructor by Ulrich

Ulrich
Wed Apr 16 09:01:31 CDT 2008

Vladimir Grigoriev wrote:
> "Igor Tandetnik" <itandetnik@mvps.org> wrote in message
> news:Of7T9z7nIHA.3804@TK2MSFTNGP02.phx.gbl...
>> The compiler may choose to elide the copy constructor no matter what it's
>> doing (in fact, without even knowing what it's doing, since its
>> implementation may be in a different source file).
>
> It is awful is not it?

I think not...

> So the statements is not equivalent
>
> B b1( a );
> B b2 = b1;
>
> and
>
> B b2 = B( a );
>
> I think it is a big gap in the standard which in essence is a source of
> hard found errors.

This isn't as bad as it sounds. Consider this code:

Object function() {
Object local;
..
return local;
}
Object other = function();

The point is that in this code already it is not specified how often you
actually copy an object. It is create once inside 'function()', then, while
returning it from the function, it might be copied and then during
initialisation of 'other' it might be copied again. OTOH, a smart compiler
can figure out that there is no need for more than one object at a time and
condense all the three objects into the same one, eliding two calls to the
copy constructor.

Now, if your copy constructor actually does anything but copying, I would
personally say that your code is obfuscated and that you should rather fix
your code.

> According to the logic we have that
>
> T x = value;
> T y = x;
>
> and
>
> T z = value;
>
> will give the result of z != y.

Hmmm, what do you need 'z' for? Shouldn't already be 'x!=y'? In any case, it
is the logic of the class 'T' that is flawed IMHO. A value should not care
what it is initialised from, it should only care for its value.


Just wondering, but what is the actual case that prompted you to start this
thread? Is this merely interest or do you have an actual case that breaks
due to the compiler eliding calls to the copy constructor?

Uli

--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Michael Wöhrmann, Amtsgericht Hamburg HR B62 932

Re: The C++ standard's rule for selecting a constructor by Vladimir

Vladimir
Wed Apr 16 09:15:18 CDT 2008


"Ulrich Eckhardt" <eckhardt@satorlaser.com> wrote in message
news:sedhd5-qg2.ln1@satorlaser.homedns.org...

> Just wondering, but what is the actual case that prompted you to start
> this
> thread? Is this merely interest or do you have an actual case that breaks
> due to the compiler eliding calls to the copy constructor?
>

It is a pure interest.

Vladimir Grigoriev



Re: The C++ standard's rule for selecting a constructor by Cezary

Cezary
Wed Apr 16 09:13:44 CDT 2008

Vladimir Grigoriev wrote:
> "Igor Tandetnik" <itandetnik@mvps.org> wrote in message

> T x = value;

T::T(valuetype value); or valuetype::T(); is called, and optionally
T::T(const T&); is called.

> T y = x;

T::T(const T&); is called

> and

> T z = value;

T::T(valuetype value); or valuetype::T(); is called, and optionally
T::T(const T&); is called.

> will give the result of z != y.

If and only if copy constructor of T will do something else then copying
of object's values. This is not so good programming practice to
implement changing of values of object (or something else) in the copy
ctor. Usually copy means _exact_ copy, but if you want to play with some
strange behaviors of copy ctors then you have what you want - do not be
surprised ;) If your initials are not B.S. then it is better if you will
avoid all strangisms in your code ;)

-- best regards

Cezary Noweta

Re: The C++ standard's rule for selecting a constructor by Cezary

Cezary
Wed Apr 16 09:36:31 CDT 2008

Hello,

Cezary H. Noweta wrote:
> ... or valuetype::T(); is ...

Certainly, it should be valuetype::operator T();

--best regards

Cezary Noweta