When Do We Have to Use Copy Constructors

When do we have to use copy constructors?

The copy constructor generated by the compiler does member-wise copying. Sometimes that is not sufficient. For example:

class Class {
public:
Class( const char* str );
~Class();
private:
char* stored;
};

Class::Class( const char* str )
{
stored = new char[srtlen( str ) + 1 ];
strcpy( stored, str );
}

Class::~Class()
{
delete[] stored;
}

in this case member-wise copying of stored member will not duplicate the buffer (only the pointer will be copied), so the first to be destroyed copy sharing the buffer will call delete[] successfully and the second will run into undefined behavior. You need deep copying copy constructor (and assignment operator as well).

Class::Class( const Class& another )
{
stored = new char[strlen(another.stored) + 1];
strcpy( stored, another.stored );
}

void Class::operator = ( const Class& another )
{
char* temp = new char[strlen(another.stored) + 1];
strcpy( temp, another.stored);
delete[] stored;
stored = temp;
}

Why do we need copy constructor and when should we use copy constructor in java

There are 2 good reasons for using a copy constructor instead of the constructor passing all parameters :

  1. when you have a complex object with many attributes it is much simpler to use the copy constructor
  2. if you add an attribute to your class, you just change the copy constructor to take this new attribute into account instead of changing every occurence of the other constructor

why are copy constructors needed and what are the cases where they are very helpful?

if you pass your objects to methods via pass by copy, c++ must use a copy constructor to generate the instance of that class for the method context. for example, if you store your instances in a vector, when you push back an object it indirectly calls the copy constructor. By the way, for classes c++ generally creates a default copy constructor if there is no explicitly implemented one, this case some times creates unwanted effects (shallow copy).

How are copy constructors used and why are they important?


What is a copy constructor?

Quoting the C++11 standard, §12.8/2:

“A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&,
volatile X& or const volatile X&, and either there are no other parameters or else all other parameters
have default arguments”

So there are 4 different forms. Of these the X const& form is the one most often used. This is also the form of the implicit copy constructor that is generated (if possible) if no copy constructor is declared for the class.

A copy constructor is used for copying an object to a new instance of the class. A default copy constructor performs a member-wise copy, which is different from and more safe than just copying the bits. In particular a copy constructor or move constructor is logically used for a copy initialization, an initialization using the = sign like

Some_type x = expression;

In some circumstances the compiler is allowed to assume that copying is all that a copy constructor does, regardless of what it actually does. Logically needless copy constructions can then be removed, or as the standard calls it, elided. For example, if the expression above is the number 42, then instead of using that argument to construct a temporary and copying or moving that to x, the argument may be used to initialize x directly.

However, even when that is done, so that the copy constructor is not used, if the copy constructor would have been used except for the optimization then a copy constructor must exist and be accessible.

C++11 §12.2/1:

“Even when the creation of the temporary object is unevaluated (Clause 5)
or otherwise avoided (12.8), all the semantic restrictions shall be respected as if the temporary object had
been created and later destroyed.”


Is it necessary to call a destructor?

Re “Is it necessary to call a destructor if we [use a copy constructor]? ”.

Generally no.

Destructors in C++ are called automatically when an object goes out of scope or when it's indirectly or directly destroyed via delete. The only exception is for placement new, which is a low level feature that has nothing in particular to do with copy constructors. Although placement new can involve copy construction.


A difference between C++03 and C++11 copy constructors.

To understand the difference between C++03 and C++11 regarding copy constructors you must be aware of three facts:

  • If a copy constructor isn’t declared, then it’s generated if possible. Hence by default every class has a copy constructor. It’s there.

  • Access is independent of overload resolution.

    Overload resolution chooses between all member functions, regardless of whether they’re accessible or not. Then access is checked. At that point you may get an error message about calling an inaccessible function, despite an expectation that overload resolution ideally should choose only from the accessible functions…

  • An ordinary function (or just function) is a better match than a an instantiation of a function template with the same signature.

Here is an example of overloading resolution choosing a private member function, in spite of a public function that could be called:


File [access_versus_overload_resolution.cpp]

 

class C
{
public:
void foo( double );
void foo( int );

void bar( double );
private:
void bar( int );
};

int main()
{
C().foo( 42 ); // OK.
C().bar( 42 ); //! Uh oh, inaccessible.
}

And here is an example of an ordinary function trumping a template instantiation:


File [function_versus_template.cpp]

 

using One = char[1];
using Two = char[2];

auto foo( char const* ) -> One&;
auto foo( char const (&)[10] ) -> Two&;

auto bar( char const* ) -> One&;

template< int n >
auto bar( char const (&)[n] ) -> Two&;

#include <iostream>
auto main() -> int
{
using namespace std;
//cout << sizeof( foo( "Blah blah" ) ) << endl; //! Ambiguous
cout << sizeof( bar( "Blah blah" ) ) << endl; // "1"
}

With these facts at hand:

  • An inaccessible copy constructor will be chosen even if there is an accessible member function template that is just as good a match.

    (As a logical consequence of the general overload resolution rules.)

  • In C++11, a member function template instantiation will therefore be chosen only if it is a better match than the copy constructor, if any.

  • But in C++03 there was a special rule that ensured that with a conforming compiler a function member template would never be used to copy an object.

Here’s the C++03 wording, §12.8/3 in that standard, where I’ve added suitable emphasis:

“A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-
qualified) X and either there are no other parameters or else all other parameters have default arguments. A
member function template is never instantiated to perform the copy of a class object to an object of its class
type.

while in C++11 the wording is subtly changed, in that standard’s §12.8/6, where again I’ve added suitable emphasis:

“A declaration of a constructor for a class Xis ill-formed if its first parameter is of type (optionally cv-qualified)
X and either there are no other parameters or else all other parameters have default arguments. A member
function template is never instantiated to produce such a constructor signature.

I.e. no special injunction against function templates being used to copy objects in C++11.

Unfortunately for history buffs, the most readily available C++03 compiler for Windows, namely MinGW g++ of some old version such as 3.2, does not enforce the C++03 rule.


File [template_versus_cc.cpp]

 

class S
{
private:
S( S const& ); // No such.

public:
S() {}

template< class T >
S( T& ) {}
};

int main()
{
S sm;
S const sc;

S s1( sm ); // OK in C++11, template is better match.
S s2( sc ); //! Line 19. Copy constructor is selected, inaccessible.
}

Compiling with old g++:


[H:\dev\test\copy_construction]
> \bin\MinGW_3_1\bin\g++ --version | find "++"
g++ (GCC) 3.2.3 (mingw special 20030504-1)

[H:\dev\test\copy_construction]
> \bin\MinGW_3_1\bin\g++ -std=c++98 -pedantic template_versus_cc.cpp
template_versus_cc.cpp: In function `int main()':
template_versus_cc.cpp:4: `S::S(const S&)' is private
template_versus_cc.cpp:19: within this context

[H:\dev\test\copy_construction]
> _

By the C++03/C++98 rules the compiler should have flagged both copy initializations, at lines 18 and 19, but only flagged the latter, behaving as a C++11 compiler in this respect.

This is also what the more modern g++ 4.8.2 does, as well as Visual C++ 12.0. But a conforming C++03-compiler must diagnose both initializations.

Scott Meyers has written about this, citing two of the SO C++ Lounge dwellers as sources. Unfortunately the article yields the impressions that (1) it’s all about universal reference template arguments in C++11, and (2) there’s is no bug in g++. The former is wrong, as shown above, while the latter is literally correct. There was a bug, but as the standard has evolved, with C++11 the g++ behavior is now conforming…

What's all the fuss about C++ copy constructors?

Copy constructors and assignment operators are very important in C++ because the language has "copy semantics", that is to say when you pass a parameter or store a value in a container, a copy of the object is passed or stored. How can C++ make a copy or perform an assignment on an object? For native types it knows by itself, but for user-defined types instead it automatically generates a member-by-member copy construction or assignment.

More explicitly if you declare for example:

class P2d
{
public:
double x, y;
P2d(double x, double y) : x(x), y(y)
{ }
};

the C++ compiler automatically completes your code to

class P2d
{
public:
double x, y;
P2d(double x, double y) : x(x), y(y)
{ }

P2d(const P2d& other) : x(other.x), y(other.y)
{ }

P2d& operator=(const P2d& other)
{
x = other.x;
y = other.y;
return *this;
}
};

Are these automatically generated copy constructor and assignment operators correct for your class? In many cases yes... but of course maybe those implementations are totally wrong. Quite often for example when you have pointers contained inside your objects then just copying the pointer when you want to make a copy of the object is not the right thing to do.

You must understand that C++ does a lot of copies of objects, and you must understand what type of copy it will do for classes you defined. If the automatically generated copy is not what you need then you must either provide your own implementation, or you must tell the compiler that copying should be forbidden for your class.

You can prevent the compiler from making copies by declaring a private copy constructor and assignment operator, and by not providing an implementation. Because those are private functions and any external code that is going to use them will get a compiler error, and because you declared them but you didn't implement them you will get a link error if by mistake you end up making copies inside the class implementation.

For example:

class Window
{
public:
WindowType t;
Window *parent,
*prev_in_parent, *next_in_parent,
*first_children, *last_children;
Window(Window *parent, WindowType t);
~Window();

private:
// TABOO! - declared but not implemented
Window(const Window&); // = delete in C++11
Window& operator=(const Window&); // = delete in C++11
};

If the last part seems absurd (how can you make copies in the implementation by mistake) please note that in C++ it is very very easy to make extra copies by mistake because the language has been built around the concept of copying things around.

A golden rule is that if your class has a destructor (because it needs to do some cleanup) then most likely a member-by-member copy is not the right thing to do... and also if you have special logic to do a copy construction then a similar logic is probably needed also in assignment (and vice versa). So the rule, known as the Big Three, states that either your class has no custom destructor, no copy constructor, no assignment operator or your class should have all three of them.

This rule is so important that for example if for any special case you end up with a class that just needs a destructor (I can't think a sensible case... but let's just say you found one) then please remember to add as a comment that you thought about it and you know that the implicitly generated copy constructor and assignment operators are ok.
If you don't add a note about the other two, whoever will read your code will think that you simply forgot about them.

UPDATE

C++ is evolving and while most of what is said here is still valid now the language provides a better method to inform the compiler that copying and assignment shouldn't be allowed.

The new syntax (valid since C++11) is

struct Window {
...
Window(const Window&) = delete;
Window& operator=(const Window&) = delete;
};

Copy Constructor in C++

The types of the member variables is not important for that(1), their semantics are. The rule is simple:

If you don't provide a copy constructor, the compiler will try to generate one for you. This default-generated one will perform the default copy operation on all member variables. For class types, this means calling the copy constructor. For primitive types, this means a bitwise copy.

If the default-generated constructor does what you need, don't declare your own. If it wouldn't do what you need, declare one yourself. It is possible to create a class with non-primitive member variables and perfectly OK default copy semantics:

struct PersonId
{
std::string surname;
std::vector<std::string> givenNames;
};

Likewise, it is possible to create a class with primitive-type member variables where the default copy semantics would not be OK:

class UniqueNamed
{
int id;
UniqueNamed() : id(0) {}

public:
UniqueNamed(const UniqueNamed &src) : id(src.id + 1) {}

int getId() const { return id; }

static UniqueNamed initial;
};

So it depends on the class's semantics, not on the types of its data members.

This touches the general concept of the semantics of copying, moving & wonership, and their implementations in C++. You might want to read something about the rules of zero, three, and five.


(1) Of course, if any member variable is of a non-copyable type, and you want your class to be copyable, you have to provide the copy constructor yourself, as the default-declared one would be defined as deleted.



Related Topics



Leave a reply



Submit