Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why copy constructors are automatically generated?

7 views
Skip to first unread message

Rodrigo Strauss

unread,
Apr 9, 2005, 6:52:53 PM4/9/05
to
Sometimes, generated copy constructor just make you code buggy (when
you have member raw pointers, for example). Sometimes you don't really
want a copy constructor. I know I can create a private one, but why is
it generated? Maybe it would be better to require programmer to specify
the need for the generated one (like declaring but not implementing).

Most of times C++ compilers don't generate code and this is why it's so
fast and so flexible. Why copy constructors don't follow this
philosophy? C-language compatibility?

I've found no mention to this in the Stroustrup's FAQ. Is it so
obvious?

Rodrigo Strauss


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Mark Van Peteghem

unread,
Apr 10, 2005, 10:00:14 AM4/10/05
to
Rodrigo Strauss wrote:

>Sometimes, generated copy constructor just make you code buggy (when
>you have member raw pointers, for example). Sometimes you don't really
>want a copy constructor. I know I can create a private one, but why is
>it generated? Maybe it would be better to require programmer to specify
>the need for the generated one (like declaring but not implementing).
>
>Most of times C++ compilers don't generate code and this is why it's so
>fast and so flexible. Why copy constructors don't follow this
>philosophy? C-language compatibility?
>

I presume it is because of C compatibility, which is a very good
reason. I think it is also the fastest solution, because the
generated code will probably do a simple memcpy, and there isn't
anything faster than that. But I agree that it can make your code
buggy.

--
Mark dot Van dot Peteghem at q-mentum dot com
http://www.q-mentum.com -- easier and more powerful unit testing

Kim, Seungtai

unread,
Apr 10, 2005, 3:16:26 PM4/10/05
to
"Mark Van Peteghem"
> ...because the

> generated code will probably do a simple memcpy, and there isn't
> anything faster than that. ...

The generated copy-constructor dose not use the memcpy for copying
object. It dose memberwise copy for all the subobjects by the other
copy-ctors and (user-defined) assignment operators.

--
S Kim <st...@yujinrobot.com>

Antoun Kanawati

unread,
Apr 10, 2005, 3:16:49 PM4/10/05
to
Mark Van Peteghem wrote:
>>Sometimes, generated copy constructor just make you code buggy (when
>>you have member raw pointers, for example). Sometimes you don't really
>>want a copy constructor. I know I can create a private one, but why is
>>it generated? Maybe it would be better to require programmer to specify
>>the need for the generated one (like declaring but not implementing).
>>
>>Most of times C++ compilers don't generate code and this is why it's so
>>fast and so flexible. Why copy constructors don't follow this
>>philosophy? C-language compatibility?
>>
> I presume it is because of C compatibility, which is a very good
> reason. I think it is also the fastest solution, because the
> generated code will probably do a simple memcpy, and there isn't
> anything faster than that. But I agree that it can make your code
> buggy.
>

The memcpy semnatics have not been used for a very long time. C++
uses member-wise copy/assignment semantics.

Also, if I recall correctly, the copy/assign generation had to do more
with making user defined types behave like builtin types, which can
be copied and assigned. That would be the "philosophical" aspect.

As for bugginess: C++ has always generated copy-ctor and op= if the
programmer did not define them; so, as long as you keep that in the
foreground, instead of the background, it's hard to forget about it
and get into the buggy situation. The extra bugginess is usually
because the need to manage copy/assign is left as an afterthought, or
"discovered" while debugging a [detected] runtime problem.
--
A. Kanawati
NO.anto...@comcast.net

Ron Natalie

unread,
Apr 10, 2005, 6:39:10 PM4/10/05
to
Antoun Kanawati wrote:

>
>
> The memcpy semnatics have not been used for a very long time. C++
> uses member-wise copy/assignment semantics.
>

Of course, if the members have simple copy semantics (i.e., the whole
thing is POD), the compiler will tend to use a block move that may in
fact be faster than the generic memcpy as assumptions can be made about
the size and the alignment.

Rob

unread,
Apr 11, 2005, 3:02:22 AM4/11/05
to
Rodrigo Strauss wrote:

> Sometimes, generated copy constructor just make you code buggy (when
> you have member raw pointers, for example). Sometimes you don't really
> want a copy constructor. I know I can create a private one, but why is
> it generated? Maybe it would be better to require programmer to
> specify the need for the generated one (like declaring but not
> implementing).
>
> Most of times C++ compilers don't generate code and this is why it's
> so fast and so flexible. Why copy constructors don't follow this
> philosophy? C-language compatibility?
>
> I've found no mention to this in the Stroustrup's FAQ. Is it so
> obvious?
>

Most obvious reason is C compatibility. C supports assignment of
structs by default, therefore C++ must for (at a minimum) support
it for POD types. In practice, supporting it for POD types but
not for other types, would be an anomoly in the language for
compiler writers to deal with and to frustrate programmers.

The default generated copy constructor for all types is "member-wise
copy" semantics. The only cause of inefficiency in that is related
to the fact that this means calling user-defined constructors (if
any).

AS to it causing bugs: the basic rule of thumb is that anything
which involves sharing a raw pointer between two objects can
introduce bugs. If you're doing such things, the process of
designing the class should identify that it has raw pointers,
so there needs to be some thought as to whether it requires
a copy constructor to be explicitly written, of if copying
should be disabled (eg make the copy constructor private).
And, if you do it to a copy constructor, also do it with the
assignment operator.....

Dmitry Mityugov

unread,
Apr 11, 2005, 3:34:03 AM4/11/05
to
Rodrigo Strauss wrote:
> Sometimes, generated copy constructor just make you code buggy (when
> you have member raw pointers, for example). Sometimes you don't really
> want a copy constructor. I know I can create a private one...

You can also declare (but not define) a copy constructor (not necessarily
private). This will prevent the compiler from generating it, and a linker
error will tell you if there are attempts in your code to call it. BTW, if
you don't want a copy constructor, you probably do not want an assignment
operator either. This is an example:

class CODate {
public:
...
// declared but not defined:
CODate( CODate const& date);
CODate& operator=( CODate const& date);


Dmitry

R.F. Pels

unread,
Apr 11, 2005, 9:36:15 AM4/11/05
to
Rodrigo Strauss wrote:

> Sometimes, generated copy constructor just make you code buggy (when
> you have member raw pointers, for example). Sometimes you don't really
> want a copy constructor. I know I can create a private one, but why is
> it generated?

It is to preserve the same copy and assignment semantics as primitive types.
You would be rudely surprised if objects of a class you define yourself
cannot do the same thing as let's say an int.

Looking at it from the opposite side: primitive types like int, float
etcetera also have a copy constructor and an assignment operator. It is as
if a copy constructor and an assignment operator is generated for them too.
You can for example do:

int x(5);
int y(x);

which looks very much the same as using a copy constructor to initialize an
object, or:

int p = 10;
int q = p;

which amounts to using int::operator(int& that) to initialize the value.

Now, in order to prevent surprises, James Coplien tells us that a programmer
should implement a default constructor, a copy constructor, an assignment
operator and a destructor for any nontrivial class. He calls this 'Orthodox
Canonical Form'.

--
Ruurd
.o.
..o
ooo

Ivan Krivyakov

unread,
Apr 12, 2005, 2:55:43 AM4/12/05
to
"R.F. Pels" <spam...@tiscali.nl> wrote in message
news:d3dik4$4tu$1...@news2.zwoll1.ov.home.nl...

>
> You would be rudely surprised if objects of a class you define yourself
> cannot do the same thing as let's say an int.
>

No, I would not. After all, my class is not an int.
Or, if it is, why stop at copying and assignment?
Where is my automatically generated operator+, operator* and other friends?
:-)
And finally, where is that lovely weird 0 constant that always gets mixed
with NULL pointer during overloads? :-)

> Looking at it from the opposite side: primitive types like int, float
> etcetera also have a copy constructor and an assignment operator.

They have many other things as well.
I think, root of the problem is C structs, not primitive types.

>
> Now, in order to prevent surprises, James Coplien tells us that a
> programmer
> should implement a default constructor, a copy constructor, an assignment
> operator and a destructor for any nontrivial class. He calls this
> 'Orthodox
> Canonical Form'.
>

Well, from modern "defensive" programming point of view this considered
a bad thing.

In Java/C# you must know what you're doing, but if you try to do something
really stupid (at the low level), it is either impossible, or compiler will
warn you.

In C you must know what you're doing, and if you do something stupid,
so be it. No stop signs, speed limit, nobody's gonna slow you down :-)
However, if you don't explicitly do something stupid, compiler will never
silently do it for you. If you did not write it, it's not there. Zero
initialization
of statics does not count.

In C++ you must know not only what you're doing, but also what
compiler is doing on your behalf. If you do something stupid, or
if compiler does something stupid and you overlook it,
it's your fault.

I am afraid C++ got the worst combination of them all.

Ivan

Dmitry Mityugov

unread,
Apr 12, 2005, 4:58:20 PM4/12/05
to
R.F. Pels wrote:
...

> Now, in order to prevent surprises, James Coplien tells us that a
> programmer
> should implement a default constructor, a copy constructor, an assignment
> operator and a destructor for any nontrivial class. He calls this
> 'Orthodox
> Canonical Form'.

Why is there a default constructor in this list? If another constructor,
like a copy constructor, is declared for a class, the compiler will not
automatically generate a default constructor, will it?

Dmitry

Antoun Kanawati

unread,
Apr 13, 2005, 2:46:54 AM4/13/05
to
Dmitry Mityugov wrote:
> R.F. Pels wrote:
> ...
>
>>Now, in order to prevent surprises, James Coplien tells us that a
>>programmer
>>should implement a default constructor, a copy constructor, an assignment
>>operator and a destructor for any nontrivial class. He calls this
>>'Orthodox
>>Canonical Form'.
>
> Why is there a default constructor in this list? If another constructor,
> like a copy constructor, is declared for a class, the compiler will not
> automatically generate a default constructor, will it?

Correct. So, if you don't have a default ctor, you will get surprised,
unpleasantly, when you try to use the standard containers, some of which
impose default-ctor requirements on the element type.

My version of this rules is that I need to address the enumerated
methods: as in, if there is no default-ctor, it is not because I
forgot about it [usually :-]

The copy/assign/destroy are usually coupled: assign and copy are
essentially variations on a theme, and if you need to hand-code
either of them, you need to do the other as well. As for the
destructor: any time you need to hand-code copy/assign, including
inhibiting them, there is a good chance that you will need to write
the destructor yourself. Conversely, if you have a hand-coded
destructor, it is almost always the case that you will also need to
pay extra attention to copy/assign operations.
--
A. Kanawati
NO.anto...@comcast.net

ker...@mail.ru

unread,
Apr 13, 2005, 2:50:54 AM4/13/05
to
>No, I would not. After all, my class is not an int.
> Or, if it is, why stop at copying and assignment?
> Where is my automatically generated operator+, operator* and other
friends?
> :-)

Well, you're kidding - but what's really missing is
automatically-generated
operator<. I'm serious :) IMO it should recursively invoke
operator< of all members in the order of their declaration to produce a

stable lexicographical sequence. Writing this manually is boring - and
this is
even impossible to use any metaprogramming tricks here.

Bo Persson

unread,
Apr 13, 2005, 4:01:07 PM4/13/05
to

<ker...@mail.ru> skrev i meddelandet
news:1113350670.0...@z14g2000cwz.googlegroups.com...

> >No, I would not. After all, my class is not an int.
>> Or, if it is, why stop at copying and assignment?
>> Where is my automatically generated operator+, operator* and other
> friends?
>> :-)
>
> Well, you're kidding - but what's really missing is
> automatically-generated
> operator<. I'm serious :) IMO it should recursively invoke
> operator< of all members in the order of their declaration to produce
> a
>
> stable lexicographical sequence. Writing this manually is boring - and
> this is
> even impossible to use any metaprogramming tricks here.
>

But this breaks immediately for complex numbers, where you don't have an
ordering.

How will the compiler know that name-and-address records should be
sorted on the zip code while printing, and by last name while searching?


It just doesn't make any sense.


Bo Persson

Ron Natalie

unread,
Apr 13, 2005, 4:06:52 PM4/13/05
to
Antoun Kanawati wrote:

> Correct. So, if you don't have a default ctor, you will get surprised,
> unpleasantly, when you try to use the standard containers, some of which
> impose default-ctor requirements on the element type.
>

No standard container requires a default constructor. The functions
that need to use "fill" objects take an additional argument (defaulted
to a default constructed object) to copy to the "empty" position.

Antoun Kanawati

unread,
Apr 14, 2005, 3:16:58 AM4/14/05
to
Ron Natalie wrote:
> Antoun Kanawati wrote:
>>Correct. So, if you don't have a default ctor, you will get surprised,
>>unpleasantly, when you try to use the standard containers, some of which
>>impose default-ctor requirements on the element type.
>
> No standard container requires a default constructor. The functions
> that need to use "fill" objects take an additional argument (defaulted
> to a default constructed object) to copy to the "empty" position.

It's only one implementation, but that's all I have to work with.
And, it wants a default ctor.

$ cat m.cpp
#include <map>

struct Foo {
Foo(int) { }
};

int main()
{
std::map<int, Foo> m;
m[3] = Foo(42);
return 0;
}

5$ g++ -c m.cpp
..../bits/stl_map.h: In member function `_Tp& std::map<_Key, _Tp,
_Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = Foo,
_Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int,
Foo> >]':
m.cpp:10: instantiated from here
..../bits/stl_map.h:339: error: no matching function for call to `Foo::Foo()'
m.cpp:3: note: candidates are: Foo::Foo(const Foo&)
m.cpp:4: note: Foo::Foo(int)

--
A. Kanawati
NO.anto...@comcast.net

Llewelly

unread,
Apr 15, 2005, 3:19:54 AM4/15/05
to
Antoun Kanawati <ant...@comcast.net> writes:

[snip]

As it happens, the standard requires the default constructor be
called:

23.3.1.2 map element access
T& operator[](const key_type& x);
Returns: (*((insert(make_pair(x, T()))).first)).second.

Note 'T()'.

If you don't care for this behavior, the answer is to use insert() ...

Friedhelm Hoerner

unread,
Apr 15, 2005, 7:59:50 PM4/15/05
to
Antoun Kanawati <ant...@comcast.net> wrote in message news:<R8OdnXn7-a-...@comcast.com>...

> It's only one implementation, but that's all I have to work with.
> And, it wants a default ctor.
>
> $ cat m.cpp
> #include <map>
>
> struct Foo {
> Foo(int) { }
> };
>
> int main()
> {
> std::map<int, Foo> m;
> m[3] = Foo(42);
> return 0;
> }
>
> 5$ g++ -c m.cpp
> ..../bits/stl_map.h: In member function `_Tp& std::map<_Key, _Tp,
> _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = Foo,
> _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int,
> Foo> >]':
> m.cpp:10: instantiated from here
> ..../bits/stl_map.h:339: error: no matching function for call to `Foo::Foo()'
> m.cpp:3: note: candidates are: Foo::Foo(const Foo&)
> m.cpp:4: note: Foo::Foo(int)

m[3] has to be constructed out of nothing (using Foo()) before
assigning a value...

Thats something i don't like with maps: There is no way to insert a
value with "overwrite option" in one simple line if you don't have a
default constructor at hand.

You may try:

std::map<int, Foo>::iterator iter = m.find(3);
if (iter == m.end())
m.insert(std::pair<int, Foo>(3,Foo(42)));
else
iter->second = Foo(42);

but it doesn't look appealing;-)

Friedhelm Hoerner

Antoun Kanawati

unread,
Apr 16, 2005, 1:41:09 PM4/16/05
to
Friedhelm Hoerner wrote:
> Antoun Kanawati <ant...@comcast.net> wrote in message news:<R8OdnXn7-a-...@comcast.com>...
>
>>It's only one implementation, but that's all I have to work with.
>>And, it wants a default ctor.

[snip] example code showing a std::map::operator[] non-const use-case.

> m[3] has to be constructed out of nothing (using Foo()) before
> assigning a value...

The example was in response to the assertion that no standard container
requires its elements to have default ctors.

> Thats something i don't like with maps: There is no way to insert a
> value with "overwrite option" in one simple line if you don't have a
> default constructor at hand.

It could be done by introducing proxies so that the operation maps to
either an assignment, or a copy construction. But, that would mean that
the return type of operator[] is no longer a reference to the mapped
type. And that type has to be crafted so that only transient instances
can be made; otherwise, you will have object representing a partial
assignment floating around.
--
A. Kanawati
NO.anto...@comcast.net

0 new messages