Topic: Passing the result of an explicitly called constructor


Author: Biju Thomas <b_thomas@ibm.net>
Date: 1999/12/14
Raw View
John Potter wrote:
>
> : >   struct D : public B {
> : >     D(int x) {...}
> : >     ...
> : >   };
> : >
> : >   void f( const B& );
> : >
> : >   f( D(3) );
> : >
> The implementation has
> a choice of binding it to the B part of that D or of creating a
> temporary of type D const and binding to the B part of that.
>
> If there is no accessible copy ctor, the program is well formed
> in the first case and ill formed in the second case.
>
> If f contains
>    B& rp(const_cast<B&>(parm));
> the program is well behaved in the first case and has undefined
> behavior in the second case.
>
> Is it really intended that an implementation decision can make
> these changes in the validity of a program?
>

If there is no accessible copy constructor, the program is ill-formed.
Quoting from 8.5.3/5 (somewhere deep down within the rules):

  "The constructor that would be used to make the copy shall
   be callable whether or not the copy is actually done."

--
Regards,
Biju Thomas
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/12/12
Raw View
On 11 Dec 99 16:20:22 GMT, Valentin Bonnard <Bonnard.V@wanadoo.fr>
wrote:

: Tom Payne wrote:
:
: > Suppose we have:
: >
: >   struct D : public B {
: >     D(int x) {...}
: >     ...
: >   };
: >
: >   void f( const B& );
: >
: >   f( D(3) );
: >
: > AFIK, the result of D(3) is not an lvalue, but rather an rvalue of
: > class D.
:
: Correct
:
: > So, it gets copied to a temp to which f's reference
: > parameter gets bound.
:
: Why would it be copied ?

Because 8.5.3/5 allows it and the implementation felt like doing copies.

: > Does the entire D rvalue get copied, or does it
: > get sliced down to a B rvalue?
:
: Nothing is copied. There might not exist any accessible
: copy constructor anyway.

Interesting point.  I have an implementation which seems to copy
builtins but not UDTs.  In the example above, a reference of type
B const is bound to an rvalue of type D.  The implementation has
a choice of binding it to the B part of that D or of creating a
temporary of type D const and binding to the B part of that.

If there is no accessible copy ctor, the program is well formed
in the first case and ill formed in the second case.

If f contains
   B& rp(const_cast<B&>(parm));
the program is well behaved in the first case and has undefined
behavior in the second case.

Is it really intended that an implementation decision can make
these changes in the validity of a program?

John


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Tom Payne <thp@roam-thp2.cs.ucr.edu>
Date: 1999/12/10
Raw View
Suppose we have:

  struct D : public B {
    D(int x) {...}
    ...
  };

  void f( const B& );

  f( D(3) );

AFIK, the result of D(3) is not an lvalue, but rather an rvalue of
class D.  So, it gets copied to a temp to which f's reference
parameter gets bound.  Does the entire D rvalue get copied, or does it
get sliced down to a B rvalue?

Tom Payne


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Darin Adler <darin@bentspoon.com>
Date: 1999/12/10
Raw View
Tom Payne <thp@roam-thp2.cs.ucr.edu> wrote:

> Suppose we have:
>
>     struct D : public B {
>         D(int x) {...}
>         ...
>     };
>
>     void f( const B& );
>
>     f( D(3) );
>
> AFIK, the result of D(3) is not an lvalue, but rather an rvalue of
> class D.  So, it gets copied to a temp to which f's reference
> parameter gets bound.  Does the entire D rvalue get copied, or does it
> get sliced down to a B rvalue?

The entire D rvalue gets copied, but a copy is not required. The compiler is
allowed to bind the const reference parameter to the temporary.

This is described in 8.5.3/5 in the standard. It says, "If the initializer
expression is an rvalue, with T2 a class type, and 'cv1 T1' is
reference-compatible with 'cv2 T2,' the reference is bound in one of the
following ways (the choice is implementation-defined):     The reference is
bound to the object represented by the rvalue (see 3.10) or to a sub-object
within that object.     A temporary of type 'cv1 T2' [sic] is created, and a
constructor is called to copy the entire rvalue object into the temporary.
The reference is bound to the temporary or to a sub-object within the
temporary.)"

    -- Darin



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Biju Thomas <b_thomas@ibm.net>
Date: 1999/12/10
Raw View
Tom Payne wrote:
>
> Suppose we have:
>
>   struct D : public B {
>     D(int x) {...}
>     ...
>   };
>
>   void f( const B& );
>
>   f( D(3) );
>
> AFIK, the result of D(3) is not an lvalue, but rather an rvalue of
> class D.  So, it gets copied to a temp to which f's reference
> parameter gets bound.  Does the entire D rvalue get copied, or does it
> get sliced down to a B rvalue?
>

It is implementation defined, AFAICS. See the elaborate rules in 8.5.3
in the standard.

<quote>

If the initializer expression is an rvalue, with T2 a class type, and
cv1 T1  is reference compatible with  cv2 T2,  the reference is bound in
one of the following ways (the choice is implementation defined):

   -- The reference is bound directly to the object
      represented by the rvalue (see 3.10) or to
      a sub object within that object.
   -- A temporary of type  cv1 T2  [sic] is created, and a copy
      constructor is called to copy the entire rvalue object
      into the temporary. The reference is bound to the
      temporary or to a sub object within the temporary.

The appropriate copy constructor must be callable whether or not the
copy is actually done. [Example:

 struct A { };
 struct B : public A { } b;
 extern B f();
 const A& rca = f(); // Either bound directly or
 // the entire B object is copied and
 // the reference is bound to the
 // A sub object of the copy

  end example]

</quote>

--
Regards,
Biju Thomas


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/12/11
Raw View
Tom Payne wrote:

> Suppose we have:
>
>   struct D : public B {
>     D(int x) {...}
>     ...
>   };
>
>   void f( const B& );
>
>   f( D(3) );
>
> AFIK, the result of D(3) is not an lvalue, but rather an rvalue of
> class D.

Correct

> So, it gets copied to a temp to which f's reference
> parameter gets bound.

Why would it be copied ?

> Does the entire D rvalue get copied, or does it
> get sliced down to a B rvalue?

Nothing is copied. There might not exist any accessible
copy constructor anyway.

--

Valentin Bonnard
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "TiTi" <T.T@Somewhere.In.Space>
Date: 1999/12/11
Raw View
>   struct D : public B {
>     D(int x) {...}
>     ...
>   };
>   void f( const B& );
>   f( D(3) );
> AFIK, the result of D(3) is not an lvalue, but rather an rvalue of
> class D.  So, it gets copied to a temp to which f's reference
> parameter gets bound.  Does the entire D rvalue get copied, or does it
> get sliced down to a B rvalue?

The standard states (8.5.3 References, p147-148):

"
...
A reference to some type "cv1 T1" is initialized by an expression of type
"cv2 T2" as follows:
* If the initializer expression (of type "cv2 T2")
- is an lvalue (...) and "cv1 T1" is reference-compatible with "cv2 T2", or
- has a class type  and can be implicitely converted to an lvalue of type
"cv3 T3", where "cv1 T1" is reference-compatible with "cv3 T3" (...).
...
"

A little example follows, which makes things more clear:

"
struct C1{};
struct C2 : C1 {} c2;
C1& rc1 = c2;        // rc1 refers to C1 sub-object in c2
const C1& crc1 = c2;        // crc1 refers to C1 sub-object c2
"

As for the doubt on the "lvalue"-ness of the temporary object you created:
"An lvalue refers to an object or a function" [standard; 3.10]
Since you created an object, an lvalue can be created from it (the reference
in this case).


TT
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]