Copy constructor problem

W

wij

Hi:
I don't understand why the following program doesn't compile.
Can anyone explain?

/* Build: g++ t.cpp */
#include <iostream>

class Foo {
Foo(const Foo& rhs) { std::cout << "Foo(const Foo&) "; };
public:
Foo(int) { std::cout << "Foo(int) "; };
};

static Foo tab[1]={ Foo(0) };

int main(void)
{
return(0);
}

g++ says error: `Foo::Foo(const Foo&)' is private
But, if the copy constructor is made public, then
the executable prints 'Foo(int) '.

$g++ t.cpp
$./a.out
Foo(int)

It looked that only Foo(int) is called, the copy constructor is
never used. But, if I hide the copy constructor, g++ complains.
How can I hide the copy constructor in this case?

IJ. Wang
 
J

Jerry Coffin

[ ... ]
It looked that only Foo(int) is called, the copy constructor is
never used. But, if I hide the copy constructor, g++ complains.
How can I hide the copy constructor in this case?

The compiler is allowed to optimize away the call to the copy ctor --
but since the copy ctor was supposed to have been used, it's required
to be available.

There's not much to do about this: if you want to be able to copy
objects, their copy ctor has to be available, and the fact that the
compiler might optimize away its use doesn't change that.
 
W

wij

Jerry Coffin 寫é“:
...
The compiler is allowed to optimize away the call to the copy ctor --
but since the copy ctor was supposed to have been used, it's required
to be available.
...

Do you mean the expression require a Foo copy constructor be defined,
and may be invoked?

static Foo tab[1]={ Foo(0) };


IJ. Wang
 
F

Frederick Gotham

IJ. Wang posted:
It looked that only Foo(int) is called, the copy constructor is
never used. But, if I hide the copy constructor, g++ complains.
How can I hide the copy constructor in this case?


Basically you're asking:

How can I initialise array members separatly if the copy-constructor
isn't public?

This is a shortcoming in the C++ programming language.

I believe you would have to resort to more drastic measures, perhaps even
something like:

#include <new>
#include <iostream>

using std::cout;

#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>

using boost::alignment_of;
using boost::aligned_storage;

class MyClass {
private:

int *const p;

MyClass(MyClass const &); /* Can't copy-construct! */

public:

MyClass(char const*) : p(new int)
{
cout << "Constructing!\n";
}

~MyClass()
{
delete p;

cout << "Destructing!\n";
}
};

int main()
{
aligned_storage<sizeof(MyClass)*5,
alignment_of<MyClass>::value> mem;

{
MyClass *p = reinterpret_cast<MyClass*>(&mem);

::new(p++) MyClass("a");
::new(p++) MyClass("b");
::new(p++) MyClass("c");
::new(p++) MyClass("d");
::new(p++) MyClass("e");
}

{
MyClass *p = reinterpret_cast<MyClass*>(&mem);

p++->~MyClass();
p++->~MyClass();
p++->~MyClass();
p++->~MyClass();
p++->~MyClass();
}
}
 
B

Bo Persson

<[email protected]> skrev i meddelandet
Jerry Coffin ??:
Do you mean the expression require a Foo copy constructor be defined,
and may be invoked?

static Foo tab[1]={ Foo(0) };

Yes. Foo(0) constructs a Foo object, that is copied to tab. That
requires both a converting constructor (from int) and a copy
constructor.

As s special rule in this case, the compiler is explicitly allowed
(but not required) to construct the Foo object directly into tab, and
optimize away the call to the copy constructor. It is required though
to first check that there *is* a copy constructor available -
otherwise the code would not be ok.


Bo Persson
 
B

benben

Basically you're asking:

How can I initialise array members separatly if the copy-constructor
isn't public?

This is a shortcoming in the C++ programming language.

I believe you would have to resort to more drastic measures, perhaps even
something like:
[low level code snipped]

I always have faith in befriending a function if certain features of the
class isn't public, like so:

#include <iostream>

class Foo;

Foo* tab(void);

class Foo {
Foo(const Foo& rhs) { std::cout << "Foo(const Foo&) "; }
public:
Foo(int) { std::cout << "Foo(int) "; }

friend Foo* tab(void);
};

Foo* tab(void)
{
static Foo _tab[1]={ Foo(0) };
return _tab;
}

int main(void)
{
Foo* bar = tab();
return(0);
}

Regards,
Ben
 
V

Victor Bazarov

benben said:
Basically you're asking:

How can I initialise array members separatly if the
copy-constructor isn't public?

This is a shortcoming in the C++ programming language.

I believe you would have to resort to more drastic measures, perhaps
even something like:
[low level code snipped]

I always have faith in befriending a function if certain features of
the class isn't public, like so:

#include <iostream>

class Foo;

Foo* tab(void);

class Foo {
Foo(const Foo& rhs) { std::cout << "Foo(const Foo&) "; }
public:
Foo(int) { std::cout << "Foo(int) "; }

friend Foo* tab(void);
};

Foo* tab(void)
{
static Foo _tab[1]={ Foo(0) };
return _tab;
}

int main(void)
{
Foo* bar = tab();
return(0);
}

That works. Of course, if you could make your 'tab' function a member
(a static member) of the class, there would be no need for the friend
declaration and the use would be almost the same:

int main()
{
Foo* bar = Foo::tab();
}

Of course, there is another curious thing about your 'tab' function -
it doesn't construct another object if called again, it just returns
the address of the same object. This is known as "a singleton". I
didn't see the original post, maybe that was a requirement.

V
 
W

wij

Bo Persson 寫é“:
...
Do you mean the expression require a Foo copy constructor be defined,
and may be invoked?

static Foo tab[1]={ Foo(0) };

Yes. Foo(0) constructs a Foo object, that is copied to tab. That
requires both a converting constructor (from int) and a copy
constructor.

As s special rule in this case, the compiler is explicitly allowed
(but not required) to construct the Foo object directly into tab, and
optimize away the call to the copy constructor. It is required though
to first check that there *is* a copy constructor available -
otherwise the code would not be ok.

Thanks Bo. I rewrote t.cpp according to your explanation.
The copy constructor is just declared. Effect is fine.

/* Build: g++ t.cpp */
#include <iostream>

class Foo {
public:
Foo(const Foo& rhs); // No definition
Foo(int) { std::cout << "Foo(int) "; };
};

static Foo tab[1]={ Foo(0) };

int main(void)
{
return(0);
}

IJ. Wang
 
J

Jerry Coffin

[ ... ]
Thanks Bo. I rewrote t.cpp according to your explanation.
The copy constructor is just declared. Effect is fine.

I wouldn't bother to declare it either -- the copy ctor is among
those that the compiler will automatically declare and (if necessary)
define for you.

Keep in mind, however, that for this to be portable, the copy ctor
defined by the compiler has to work correctly. Right now, it's
optimizing away the use of the copy ctor, but almost any change in
your build setup (e.g. new compiler, different compiler, even
different flags to the current compiler) might change that and the
copy ctor would actually be used. When/if that happens, you want to
be sure it'll continue to work correctly.
 
W

wij

Jerry Coffin 寫é“:
I wouldn't bother to declare it either -- the copy ctor is among
those that the compiler will automatically declare and (if necessary)
define for you.

Keep in mind, however, that for this to be portable, the copy ctor
defined by the compiler has to work correctly. Right now, it's
optimizing away the use of the copy ctor, but almost any change in
your build setup (e.g. new compiler, different compiler, even
different flags to the current compiler) might change that and the
copy ctor would actually be used. When/if that happens, you want to
be sure it'll continue to work correctly.

The design requirement is that copy constructor can't be invoked in
initializing the array element. Declaring the copy constructor
without definition might make the compiler warn if it is going to
use a copy constructor (vs no declaration at all).

I am wondering if it is a theoratical issue, since programmer (me)
hardly expect a copy constructor invoked from the expression:
static Foo tab[1]={ Foo(0) };

Or is there any compiler/flags causing invoke of copy constructor
in the above array element initialization?


IJ. Wang
 
V

Victor Bazarov

[..]
I am wondering if it is a theoratical issue, since programmer (me)
hardly expect a copy constructor invoked from the expression:
static Foo tab[1]={ Foo(0) };

Let me ask you this. Do you expect a copy-constructor to be used
here:

Foo foo = 0;

??? Yet, if it isn't available, the compiler will flag your code
as ill-formed. It's not theoretical. It's how the language is
standardized.
Or is there any compiler/flags causing invoke of copy constructor
in the above array element initialization?

We don't discuss any particular implementation's command-line
options here.

V
 
J

Jerry Coffin

[ ... ]
The design requirement is that copy constructor can't be invoked in
initializing the array element. Declaring the copy constructor
without definition might make the compiler warn if it is going to
use a copy constructor (vs no declaration at all).

I suppose it might -- compilers have certainly given warnings about
stranger things than that at times.
I am wondering if it is a theoratical issue, since programmer (me)
hardly expect a copy constructor invoked from the expression:
static Foo tab[1]= { Foo(0) };

You should expect it -- that's exactly what the standard says should
happen. It gives permission to optimize it away, but the basic model
is that whatever's to the right of the '=' should be constructed, and
then a copy ctor should be used to create the left side with that
value.
Or is there any compiler/flags causing invoke of copy constructor
in the above array element initialization?

Hopefully when you ask somewhere that your specific compiler is
topical they'll be able to help you with that.
 

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,774
Messages
2,569,598
Members
45,144
Latest member
KetoBaseReviews
Top