private copy constructor question

D

David Jobet

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
 
Ö

Öö Tiib

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.
 
J

Juha Nieminen

David Jobet said:
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).
 
D

David Jobet

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

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.
 
D

David Jobet

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

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.
 
D

David Jobet

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

Tx

David
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top