Copy constructor, return by value and const references

Discussion in 'C++' started by Jan Lellmann, Nov 9, 2009.

  1. Jan Lellmann

    Jan Lellmann Guest

    Hello,

    could anyone explain to me why the following code fails to compile?

    ----

    #include <iostream>
    using namespace std

    class A {
    private:
    friend A createA(); // private default constructor
    A() { cout << "default constructor" << endl; };
    A(const A& from) { // private copy constructor
    cout << "copy constructor" << endl;
    }
    public:
    int get() {
    return 1;
    }
    };


    A createA() {
    return A();
    }

    int main(int, char**)
    {
    createA().get(); // this compiles
    const A& ref(createA()); // "error: A::A(const A&) is private"
    }

    ----

    The error is the same with g++ and VC++. When the copy constructor is
    declared public instead, the code compiles but the copy constructor never
    gets called -- why?

    Regards,
    Jan
     
    Jan Lellmann, Nov 9, 2009
    #1
    1. Advertising

  2. Jan Lellmann

    Alex Guest

    On 11ÔÂ9ÈÕ, ÉÏÎç9ʱ16·Ö, Jan Lellmann <> wrote:
    > Hello,
    >
    > could anyone explain to me why the following code fails to compile?
    >
    > ----
    >
    > #include <iostream>
    > using namespace std
    >
    > class A {
    > private:
    > friend A createA(); // private default constructor
    > A() { cout << "default constructor" << endl; };
    > A(const A& from) { // private copy constructor
    > cout << "copy constructor" << endl;
    > }
    > public:
    > int get() {
    > return 1;
    > }
    >
    > };
    >
    > A createA() {
    > return A();
    >
    > }
    >
    > int main(int, char**)
    > {
    > createA().get(); // this compiles
    > const A& ref(createA()); // "error: A::A(const A&) is private"
    >
    > }
    >
    > ----
    >
    > The error is the same with g++ and VC++. When the copy constructor is
    > declared public instead, the code compiles but the copy constructor never
    > gets called -- why?
    >
    > Regards,
    > Jan

    copy constructor is called "return A() " runs
    A createA() {
    return A();


    }
     
    Alex, Nov 9, 2009
    #2
    1. Advertising

  3. Jan Lellmann

    Jan Lellmann Guest

    > copy constructor is called "return A() " runs
    > A createA() {
    > return A();
    >
    >
    > }


    Yes, that's what I would have guessed at first. But createA() is a "friend"
    so it has access to the copy constructor, which can be seen from the fact
    that the "createA().get();" line compiles.

    Also, as I wrote the copy constructor will not get called (you can check by
    making the copy constructor public and looking at the output).

    Regards,
    Jan
     
    Jan Lellmann, Nov 9, 2009
    #3
  4. Jan Lellmann

    LR Guest

    Jan Lellmann wrote:
    > Hello,
    >
    > could anyone explain to me why the following code fails to compile?
    >
    > ----
    >
    > #include <iostream>
    > using namespace std
    >
    > class A {
    > private:
    > friend A createA(); // private default constructor
    > A() { cout << "default constructor" << endl; };
    > A(const A& from) { // private copy constructor
    > cout << "copy constructor" << endl;
    > }
    > public:
    > int get() {
    > return 1;
    > }
    > };
    >
    >
    > A createA() {
    > return A();
    > }
    >
    > int main(int, char**)
    > {
    > createA().get(); // this compiles
    > const A& ref(createA()); // "error: A::A(const A&) is private"
    > }
    >
    > ----
    >
    > The error is the same with g++ and VC++. When the copy constructor is
    > declared public instead, the code compiles but the copy constructor never
    > gets called -- why?



    If I've read the standard correctly, I think that section 12.2 says that
    a copy ctor doesn't have to be called here, it can be elided by the
    compiler. But if the copy ctor isn't called the compiler still has to
    apply the rules as if it were called.

    LR
     
    LR, Nov 9, 2009
    #4
  5. Jan Lellmann

    Alex Guest

    On 11月9æ—¥, 下åˆ1æ—¶45分, LR <> wrote:
    > Jan Lellmann wrote:
    > > Hello,

    >
    > > could anyone explain to me why the following code fails to compile?

    >
    > > ----

    >
    > > #include <iostream>
    > > using namespace std

    >
    > > class A {
    > > private:
    > >      friend A createA(); // private default constructor
    > >      A() { cout << "default constructor" << endl; };
    > >      A(const A& from) {  // private copy constructor
    > >          cout << "copy constructor" << endl;
    > >      }
    > > public:
    > >      int get() {
    > >          return 1;
    > >      }
    > > };

    >
    > > A createA() {
    > >      return A();
    > > }

    >
    > > int main(int, char**)
    > > {
    > >      createA().get();         // this compiles
    > >      const A& ref(createA()); // "error: A::A(const A&) is private"
    > > }

    >
    > > ----

    >
    > > The error is the same with g++ and VC++. When the copy constructor is
    > > declared public instead, the code compiles but the copy constructor never
    > > gets called -- why?

    >
    > If I've read the standard correctly, I think that section 12.2 says that
    > a copy ctor doesn't have to be called here, it can be elided by the
    > compiler. But if the copy ctor isn't called the compiler still has to
    > apply the rules as if it were called.
    >
    > LR- éšè—被引用文字 -
    >
    > - 显示引用的文字 -


    yep, :D
     
    Alex, Nov 9, 2009
    #5
  6. Jan Lellmann

    SG Guest

    On 9 Nov., 02:16, Jan Lellmann wrote:
    >
    > using namespace std
    >
    > class A {
    > private:
    >      friend A createA(); // private default constructor
    >      A() { cout << "default constructor" << endl; };
    >      A(const A& from) {  // private copy constructor
    >          cout << "copy constructor" << endl;
    >      }
    > public:
    >      int get() {
    >          return 1;
    >      }
    > };
    >
    > A createA() {
    >      return A();
    > }
    >
    > int main(int, char**)
    > {
    >      createA().get();         // this compiles
    >      const A& ref(createA()); // "error: A::A(const A&) is private"
    > }


    The standard allows the compiler to copy a temporary to another
    temporary before binding it to a reference-to-const. Obviously you
    need to have a public copy ctor for that. C++0x will get rid of this
    rule and make your program well-formed. Some compilers don't even
    complain about these things (g++) because they always *directly* bind
    a temporary to a ref-to-const.

    Cheers,
    SG
     
    SG, Nov 9, 2009
    #6
  7. Jan Lellmann

    SG Guest

    On 9 Nov., 09:26, SG wrote:
    > On 9 Nov., 02:16, Jan Lellmann wrote:
    >
    > > using namespace std

    >
    > > class A {
    > > private:
    > >      friend A createA(); // private default constructor
    > >      A() { cout << "default constructor" << endl; };
    > >      A(const A& from) {  // private copy constructor
    > >          cout << "copy constructor" << endl;
    > >      }
    > > public:
    > >      int get() {
    > >          return 1;
    > >      }
    > > };

    >
    > > A createA() {
    > >      return A();
    > > }

    >
    > > int main(int, char**)
    > > {
    > >      createA().get();         // this compiles
    > >      const A& ref(createA()); // "error: A::A(const A&) is private"
    > > }

    >
    > The standard allows the compiler to copy a temporary to another
    > temporary before binding it to a reference-to-const. Obviously you
    > need to have a public copy ctor for that. C++0x will get rid of this
    > rule and make your program well-formed. Some compilers don't even
    > complain about these things (g++) because they always *directly* bind
    > a temporary to a ref-to-const.



    To be specific: 8.5.3 [dcl.init.ref] (Initializers, references). The
    bullet point for class-type rvalues:

    — 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 subobject 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 subobject within the temporary.

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


    In C++0x compilers are forced to go with the first option:

    — 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 to the object represented by the rvalue
    (see 3.10) or to a sub-object within that object.


    > Cheers,
    > SG
     
    SG, Nov 9, 2009
    #7
  8. Jan Lellmann

    Jan Lellmann Guest

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


    Weird, but thanks for the precise explanation.

    Best Regards,
    Jan
     
    Jan Lellmann, Nov 9, 2009
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    363
    Victor Bazarov
    Jul 29, 2005
  2. Javier
    Replies:
    2
    Views:
    621
    James Kanze
    Sep 4, 2007
  3. Rahul
    Replies:
    1
    Views:
    1,267
    Thomas Grund
    Jul 7, 2008
  4. sanjay
    Replies:
    1
    Views:
    393
    sanjay
    Oct 9, 2008
  5. cinsk
    Replies:
    35
    Views:
    2,729
    James Kanze
    Oct 11, 2010
Loading...

Share This Page