private copy constructor question

Discussion in 'C++' started by David Jobet, Nov 29, 2010.

  1. David Jobet

    David Jobet Guest

    Hello,

    here's a simple program :

    listing 1 :
    ---
    #include <stdio.h>

    class A
    {
    public :
    A() { printf("A()\n"); }
    A(bool b) { printf("A(bool)\n");}

    //private :
    A(const A&) { printf("A(const A &)\n"); }
    private :
    const A &operator =(const A &) { printf("const A &operator =(const A &);
    \n"); return *this;}
    };

    int main(int argc, char **argv)
    {
    A a0;
    A a3 = true;
    return 1;
    }
    ---

    I compile it with g++ (4.4.3 (Ubuntu 4.4.3-4ubuntu5)) and run it. Here's the
    output :
    A()
    A(bool)

    Cool, the copy constructor is not invoked.

    Now let's make a simple modification :
    (uncommenting the private access modifier in listing 1 to make the copy
    constructor private)

    listing 2
    ---
    #include <stdio.h>

    class A
    {
    public :
    A() { printf("A()\n"); }
    A(bool b) { printf("A(bool)\n");}

    private :
    A(const A&) { printf("A(const A &)\n"); }
    private :
    const A &operator =(const A &) { printf("const A &operator =(const A &);
    \n"); return *this;}
    };

    int main(int argc, char **argv)
    {
    A a0;
    A a3 = true;
    return 1;
    }
    ---

    Still compiling it with the same compiler. Here are the errors :
    test.cpp: In function ‘int main(int, char**)’:
    test.cpp:10: error: ‘A::A(const A&)’ is private
    test.cpp:18: error: within this context

    Not cool. Don't understand.
    First listing "shows" that I'm not using the copy constructor, but in
    listing 2, if I make this "not used" copy constructor private, it does not
    compile ?!!

    What am I missing here ?

    Tx

    David

    PS : oh, and I'm just copmpiling it like this :
    $> g++ test.cpp
    then invoking the output (if it compiles) from
    $> ./a.out
    David Jobet, Nov 29, 2010
    #1
    1. Advertising

  2. David Jobet

    Öö Tiib Guest

    On Nov 29, 6:10 am, David Jobet <> wrote:
    > Hello,
    >
    > here's a simple program :
    >
    > listing 1 :
    > ---
    > #include <stdio.h>
    >
    > class A
    > {
    > public :
    >   A() { printf("A()\n"); }
    >   A(bool b) { printf("A(bool)\n");}
    >
    > //private :
    >   A(const A&) { printf("A(const A &)\n"); }
    > private :
    >   const A &operator =(const A &) { printf("const A &operator =(const A &);
    > \n"); return *this;}
    >
    > };
    >
    > int main(int argc, char **argv)
    > {
    >   A a0;
    >   A a3 = true;
    >   return 1;}
    >
    > ---
    >
    > I compile it with g++ (4.4.3 (Ubuntu 4.4.3-4ubuntu5)) and run it. Here's the
    > output :
    > A()
    > A(bool)
    >
    > Cool, the copy constructor is not invoked.
    >
    > Now let's make a simple modification :
    > (uncommenting the private access modifier in listing 1 to make the copy
    > constructor private)
    >
    > listing 2
    > ---
    > #include <stdio.h>
    >
    > class A
    > {
    > public :
    >   A() { printf("A()\n"); }
    >   A(bool b) { printf("A(bool)\n");}
    >
    > private :
    >   A(const A&) { printf("A(const A &)\n"); }
    > private :
    >   const A &operator =(const A &) { printf("const A &operator =(const A &);
    > \n"); return *this;}
    >
    > };
    >
    > int main(int argc, char **argv)
    > {
    >   A a0;
    >   A a3 = true;
    >   return 1;}
    >
    > ---
    >
    > Still compiling it with the same compiler. Here are the errors :
    > test.cpp: In function ‘int main(int, char**)’:
    > test.cpp:10: error: ‘A::A(const A&)’ is private
    > test.cpp:18: error: within this context
    >
    > Not cool. Don't understand.
    > First listing "shows" that I'm not using the copy constructor, but in
    > listing 2, if I make this "not used" copy constructor private, it does not
    > compile ?!!
    >
    > What am I missing here ?


    It is about optimization. As result of the optimization copy
    initialization works like direct initialization. It is OK because
    compiler is allowed to optimize copy construction out when copy
    initializing. Copy constructor must be still accessible. Same thing
    happens with return value optimization ... copying may be optimized
    out, copy constructor must be still accessible.
    Öö Tiib, Nov 29, 2010
    #2
    1. Advertising

  3. David Jobet <> wrote:
    > Cool, the copy constructor is not invoked.


    Just because it's not being called doesn't mean it's not required, as
    per the language definition. In this case, it is required (but the
    compiler is allowed to skip calling it).
    Juha Nieminen, Nov 29, 2010
    #3
  4. David Jobet

    David Jobet Guest

    OK, makes sense, never thought of that as an optimization, I thought it was
    in the spec and did not understand it completly obviously.
    The comparison with the return value optimization helped.

    Tx very much for the answer.

    I have an additional question : I have been implementing the c++0x atomic
    lib out of despair of finding it available on the web someplace else.
    (you can find it here when the website works :
    http://david.jobet.free.fr/wiclear-blog/)

    The gcc "c++0x" version works fine, and I'm now trying to adapt it to make
    it work with c++98.
    Problem, the copy constructor is private. (as well as the assignment
    operator)
    So how do you suggest I make user code compiles unchanged in c++98 mode ?

    For example :
    std::atomic_flag af = ATOMIC_FLAG_INIT;

    Where I changed the definition of ATOMIC_FLAG_INIT from "{false}" in c++0x
    to just "false" in c++98.

    Do you have any advice ?

    David

    PS : also tx to Juha Nieminen in the other thread.

    Öö Tiib wrote:
    > It is about optimization. As result of the optimization copy
    > initialization works like direct initialization. It is OK because
    > compiler is allowed to optimize copy construction out when copy
    > initializing. Copy constructor must be still accessible. Same thing
    > happens with return value optimization ... copying may be optimized
    > out, copy constructor must be still accessible.
    David Jobet, Nov 30, 2010
    #4
  5. David Jobet

    David Jobet Guest

    A direct link may help : http://david.jobet.free.fr/wiclear-
    blog/images/atomic-2010-11-26.tgz

    David Jobet wrote:

    > OK, makes sense, never thought of that as an optimization, I thought it
    > was in the spec and did not understand it completly obviously.
    > The comparison with the return value optimization helped.
    >
    > Tx very much for the answer.
    >
    > I have an additional question : I have been implementing the c++0x atomic
    > lib out of despair of finding it available on the web someplace else.
    > (you can find it here when the website works :
    > http://david.jobet.free.fr/wiclear-blog/)
    >
    > The gcc "c++0x" version works fine, and I'm now trying to adapt it to make
    > it work with c++98.
    > Problem, the copy constructor is private. (as well as the assignment
    > operator)
    > So how do you suggest I make user code compiles unchanged in c++98 mode ?
    >
    > For example :
    > std::atomic_flag af = ATOMIC_FLAG_INIT;
    >
    > Where I changed the definition of ATOMIC_FLAG_INIT from "{false}" in c++0x
    > to just "false" in c++98.
    >
    > Do you have any advice ?
    >
    > David
    >
    > PS : also tx to Juha Nieminen in the other thread.
    >
    > Öö Tiib wrote:
    >> It is about optimization. As result of the optimization copy
    >> initialization works like direct initialization. It is OK because
    >> compiler is allowed to optimize copy construction out when copy
    >> initializing. Copy constructor must be still accessible. Same thing
    >> happens with return value optimization ... copying may be optimized
    >> out, copy constructor must be still accessible.
    David Jobet, Nov 30, 2010
    #5
  6. David Jobet

    Öö Tiib Guest

    On Nov 30, 5:28 am, David Jobet <> wrote:
    >
    > I have an additional question : I have been implementing the c++0x atomic
    > lib out of despair of finding it available on the web someplace else.
    > (you can find it here when the website works :http://david.jobet.free.fr/wiclear-blog/)
    >
    > The gcc "c++0x" version works fine, and I'm now trying to adapt it to make
    > it work with c++98.
    > Problem, the copy constructor is private. (as well as the assignment
    > operator)
    > So how do you suggest I make user code compiles unchanged in c++98 mode ?


    C++0x will have std::atomic<> in it, C++98 does not contain any
    support for atomic operations (or even threads).

    When atomic operations are needed for C++98 or C++03 code then my
    first suggestion is to use platform support.

    If it needs to be portable C++98 code then simplest is perhaps to take
    some library that supports atomic operations on multiple platforms.
    Boehm garbage collector for example contains such libatomic_ops part
    that works on lot of popular platforms.
    Öö Tiib, Nov 30, 2010
    #6
  7. David Jobet

    David Jobet Guest

    Let me clarify :
    - I don't want to use a 3rd party lib since c++0x is nearly there. I'd like
    to base my code on it right now so I don't have to port my code to it when
    it's available
    - I could use the boost impl of the atomic lib, but the implementation is
    partial and I'm not sure I agree with the impl
    - I could buy the lib from Anthony Williams http://www.stdthread.co.uk/, and
    I would better trust his lib than others, but I tend to prefer open source
    (even if I understand the motivation to sell it)
    - so instead since this lib can be entirely implemented without any help
    from the compiler, I implemented it myself. It took me some time, but it was
    great. I now have a good understanding of the different c++ memory models,
    and this was not easy ! ;-)

    So since this lib can be implemented without any special support from the
    compiler, making it work for c++0x or for c++98 is just a matter of
    - changing "deleted" constructors/operators in c++0x to private signature in
    c++98
    - changing "default" constructor impl in c++0x to inline impl in c++98
    - ignoring the constexpr declarator
    - ...

    The only thing which makes me choke right now is the deleted copy
    constructor and the deleted assignment operator.

    Because of them, I cannot write easily
    std::atomic_flag af = ATOMIC_FLAG_INIT;

    According to the spec, the macro ATOMIC_FLAG_INIT expands to "something"
    allowing to initialize the atomic_flag to a clear state.

    In c++0x it just expands to {false}, and it works thanks to the support for
    initializer list.
    This does not work in c++98, so I tried to change it to "false", hoping it
    would go through the constructor, but then I found out the private copy
    constructor forbids the initialization.

    So I was just hoping to get an idea from you about getting around that
    problem.

    Just found it while typing this message : instead of declaring the inner
    value private, I can make it public, then I can use the {false}
    initialization while still forbiding copying...

    I'm breaking a little bit the encapsulation, but the API remains mostly
    unchanged.

    Tx

    David


    Öö Tiib wrote:

    > On Nov 30, 5:28 am, David Jobet <> wrote:
    >>
    >> I have an additional question : I have been implementing the c++0x atomic
    >> lib out of despair of finding it available on the web someplace else.
    >> (you can find it here when the website works
    >> :http://david.jobet.free.fr/wiclear-blog/)
    >>
    >> The gcc "c++0x" version works fine, and I'm now trying to adapt it to
    >> make it work with c++98.
    >> Problem, the copy constructor is private. (as well as the assignment
    >> operator)
    >> So how do you suggest I make user code compiles unchanged in c++98 mode ?

    >
    > C++0x will have std::atomic<> in it, C++98 does not contain any
    > support for atomic operations (or even threads).
    >
    > When atomic operations are needed for C++98 or C++03 code then my
    > first suggestion is to use platform support.
    >
    > If it needs to be portable C++98 code then simplest is perhaps to take
    > some library that supports atomic operations on multiple platforms.
    > Boehm garbage collector for example contains such libatomic_ops part
    > that works on lot of popular platforms.
    David Jobet, Dec 1, 2010
    #7
  8. David Jobet

    David Jobet Guest

    OK, forget about that solution, this works only with an empty class...

    David Jobet wrote:

    > Let me clarify :
    > - I don't want to use a 3rd party lib since c++0x is nearly there. I'd
    > like to base my code on it right now so I don't have to port my code to it
    > when it's available
    > - I could use the boost impl of the atomic lib, but the implementation is
    > partial and I'm not sure I agree with the impl
    > - I could buy the lib from Anthony Williams http://www.stdthread.co.uk/,
    > and I would better trust his lib than others, but I tend to prefer open
    > source (even if I understand the motivation to sell it)
    > - so instead since this lib can be entirely implemented without any help
    > from the compiler, I implemented it myself. It took me some time, but it
    > was great. I now have a good understanding of the different c++ memory
    > models, and this was not easy ! ;-)
    >
    > So since this lib can be implemented without any special support from the
    > compiler, making it work for c++0x or for c++98 is just a matter of
    > - changing "deleted" constructors/operators in c++0x to private signature
    > in c++98
    > - changing "default" constructor impl in c++0x to inline impl in c++98
    > - ignoring the constexpr declarator
    > - ...
    >
    > The only thing which makes me choke right now is the deleted copy
    > constructor and the deleted assignment operator.
    >
    > Because of them, I cannot write easily
    > std::atomic_flag af = ATOMIC_FLAG_INIT;
    >
    > According to the spec, the macro ATOMIC_FLAG_INIT expands to "something"
    > allowing to initialize the atomic_flag to a clear state.
    >
    > In c++0x it just expands to {false}, and it works thanks to the support
    > for initializer list.
    > This does not work in c++98, so I tried to change it to "false", hoping it
    > would go through the constructor, but then I found out the private copy
    > constructor forbids the initialization.
    >
    > So I was just hoping to get an idea from you about getting around that
    > problem.
    >
    > Just found it while typing this message : instead of declaring the inner
    > value private, I can make it public, then I can use the {false}
    > initialization while still forbiding copying...
    >
    > I'm breaking a little bit the encapsulation, but the API remains mostly
    > unchanged.
    >
    > Tx
    >
    > David
    >
    >
    > Öö Tiib wrote:
    >
    >> On Nov 30, 5:28 am, David Jobet <> wrote:
    >>>
    >>> I have an additional question : I have been implementing the c++0x
    >>> atomic lib out of despair of finding it available on the web someplace
    >>> else. (you can find it here when the website works
    >>> :http://david.jobet.free.fr/wiclear-blog/)
    >>>
    >>> The gcc "c++0x" version works fine, and I'm now trying to adapt it to
    >>> make it work with c++98.
    >>> Problem, the copy constructor is private. (as well as the assignment
    >>> operator)
    >>> So how do you suggest I make user code compiles unchanged in c++98 mode
    >>> ?

    >>
    >> C++0x will have std::atomic<> in it, C++98 does not contain any
    >> support for atomic operations (or even threads).
    >>
    >> When atomic operations are needed for C++98 or C++03 code then my
    >> first suggestion is to use platform support.
    >>
    >> If it needs to be portable C++98 code then simplest is perhaps to take
    >> some library that supports atomic operations on multiple platforms.
    >> Boehm garbage collector for example contains such libatomic_ops part
    >> that works on lot of popular platforms.
    David Jobet, Dec 1, 2010
    #8
  9. David Jobet

    Öö Tiib Guest

    On Dec 1, 5:43 am, David Jobet <> wrote:
    > Let me clarify :
    > - I don't want to use a 3rd party lib since c++0x is nearly there. I'd like
    > to base my code on it right now so I don't have to port my code to it when
    > it's available
    > - I could use the boost impl of the atomic lib, but the implementation is
    > partial and I'm not sure I agree with the impl
    > - I could buy the lib from Anthony Williamshttp://www.stdthread.co.uk/, and
    > I would better trust his lib than others, but I tend to prefer open source
    > (even if I understand the motivation to sell it)
    > - so instead since this lib can be entirely implemented without any help
    > from the compiler, I implemented it myself. It took me some time, but it was
    > great. I now have a good understanding of the different c++ memory models,
    > and this was not easy ! ;-)
    >
    > So since this lib can be implemented without any special support from the
    > compiler, making it work for c++0x or for c++98 is just a matter of
    > - changing "deleted" constructors/operators in c++0x to private signature in
    > c++98
    > - changing "default" constructor impl in c++0x to inline impl in c++98
    > - ignoring the constexpr declarator
    > - ...
    >
    > The only thing which makes me choke right now is the deleted copy
    > constructor and the deleted assignment operator.
    >
    > Because of them, I cannot write easily
    > std::atomic_flag af = ATOMIC_FLAG_INIT;


    You can not copy initialize without public copy constructor. Perhaps
    remove the declaration of copy constructor under c++98 whatsoever. It
    makes your atomic_flag copyable ... but if you don't ... no harm made.
    Öö Tiib, Dec 1, 2010
    #9
  10. David Jobet

    David Jobet Guest

    Yep, tried a lot of trick to see if I could somehow bypass it, and came up
    with the same conclusion...

    Tx

    David

    Öö Tiib wrote:

    > You can not copy initialize without public copy constructor. Perhaps
    > remove the declaration of copy constructor under c++98 whatsoever. It
    > makes your atomic_flag copyable ... but if you don't ... no harm made.
    David Jobet, Dec 2, 2010
    #10
    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. Jan
    Replies:
    7
    Views:
    1,061
    Pete Becker
    Dec 6, 2005
  2. Replies:
    4
    Views:
    4,110
    Alf P. Steinbach
    Mar 3, 2006
  3. Fraser Ross
    Replies:
    7
    Views:
    539
    James Kanze
    Aug 7, 2007
  4. Generic Usenet Account
    Replies:
    10
    Views:
    2,197
  5. cinsk
    Replies:
    35
    Views:
    2,560
    James Kanze
    Oct 11, 2010
Loading...

Share This Page