Special members - C++ Tutorials
Special members - C++ Tutorials
Search: Go
Not logged in
C++
Information
Tutorials
Reference
Articles
Forum
C++ Language
Member function typical form for class C:
Introduction:
Default constructor C::C();
Compilers
Destructor C::~C();
Basics of C++:
Structure of a program
Copy constructor C::C (const C&);
Variables and types Copy assignment C& operator= (const C&);
Constants Move constructor C::C (C&&);
Operators Move assignment C& operator= (C&&);
Basic Input/Output
Program structure: Let's examine each of these:
Statements and flow control
Functions
Overloads and templates Default constructor
Name visibility The default constructor is the constructor called when objects of a class are declared, but are not initialized with any
Compound data types: arguments.
Arrays
Character sequences If a class definition has no constructors, the compiler assumes the class to have an implicitly defined default
Pointers constructor. Therefore, after declaring a class like this:
Dynamic memory
Data structures 1 class Example {
Other data types 2 public:
Classes: 3 int total;
4 void accumulate (int x) { total += x; }
Classes (I)
5 };
Classes (II)
Special members
Friendship and inheritance
The compiler assumes that Example has a default constructor. Therefore, objects of this class can be constructed by
Polymorphism
simply declaring them without any arguments:
Other language features:
Type conversions
Example ex;
Exceptions
Preprocessor directives
Standard library:
Input/output with files
But as soon as a class has some constructor taking any number of parameters explicitly declared, the compiler no
longer provides an implicit default constructor, and no longer allows the declaration of new objects of that class without
arguments. For example, the following class:
1 class Example2 {
2 public:
3 int total;
4 Example2 (int initial_value) : total(initial_value) { };
5 void accumulate (int x) { total += x; };
6 };
Here, we have declared a constructor with a parameter of type int. Therefore the following object declaration would be
correct:
Would not be valid, since the class has been declared with an explicit constructor taking one argument and that
replaces the implicit default constructor taking none.
Therefore, if objects of this class need to be constructed without arguments, the proper default constructor shall also be
declared in the class. For example:
https://www.cplusplus.com/doc/tutorial/classes2/ 1/5
6/3/2021 Special members - C++ Tutorials
15 Example3 foo;
16 Example3 bar ("Example");
17
18 cout << "bar's content: " << bar.content() << '\n';
19 return 0;
20 }
Here, Example3 has a default constructor (i.e., a constructor without parameters) defined as an empty block:
Example3() {}
This allows objects of class Example3 to be constructed without arguments (like foo was declared in this example).
Normally, a default constructor like this is implicitly defined for all classes that have no other constructors and thus no
explicit definition is required. But in this case, Example3 has another constructor:
And when any constructor is explicitly declared in a class, no implicit default constructors is automatically provided.
Destructor
Destructors fulfill the opposite functionality of constructors: They are responsible for the necessary cleanup needed by a
class when its lifetime ends. The classes we have defined in previous chapters did not allocate any resource and thus
did not really require any clean up.
But now, let's imagine that the class in the last example allocates dynamic memory to store the string it had as data
member; in this case, it would be very useful to have a function called automatically at the end of the object's life in
charge of releasing this memory. To do this, we use a destructor. A destructor is a member function very similar to a
default constructor: it takes no arguments and returns nothing, not even void. It also uses the class name as its own
name, but preceded with a tilde sign (~):
On construction, Example4 allocates storage for a string. Storage that is later released by the destructor.
The destructor for an object is called at the end of its lifetime; in the case of foo and bar this happens at the end of
function main.
Copy constructor
When an object is passed a named object of its own type as argument, its copy constructor is invoked in order to
construct a copy.
A copy constructor is a constructor whose first parameter is of type reference to the class itself (possibly const
qualified) and which can be invoked with a single argument of this type. For example, for a class MyClass, the copy
constructor may have the following signature:
If a class has no custom copy nor move constructors (or assignments) defined, an implicit copy constructor is provided.
This copy constructor simply performs a copy of its own members. For example, for a class such as:
1 class MyClass {
2 public:
3 int a, b; string c;
4 };
An implicit copy constructor is automatically defined. The definition assumed for this function performs a shallow copy,
roughly equivalent to:
This default copy constructor may suit the needs of many classes. But shallow copies only copy the members of the
https://www.cplusplus.com/doc/tutorial/classes2/ 2/5
6/3/2021 Special members - C++ Tutorials
class themselves, and this is probably not what we expect for classes like class Example4 we defined above, because it
contains pointers of which it handles its storage. For that class, performing a shallow copy means that the pointer value
is copied, but not the content itself; This means that both objects (the copy and the original) would be sharing a single
string object (they would both be pointing to the same object), and at some point (on destruction) both objects would
try to delete the same block of memory, probably causing the program to crash on runtime. This can be solved by
defining the following custom copy constructor that performs a deep copy:
The deep copy performed by this copy constructor allocates storage for a new string, which is initialized to contain a
copy of the original object. In this way, both objects (copy and original) have distinct copies of the content stored in
different locations.
Copy assignment
Objects are not only copied on construction, when they are initialized: They can also be copied on any assignment
operation. See the difference:
1 MyClass foo;
2 MyClass bar (foo); // object initialization: copy constructor called
3 MyClass baz = foo; // object initialization: copy constructor called
4 foo = bar; // object already initialized: copy assignment called
Note that baz is initialized on construction using an equal sign, but this is not an assignment operation! (although it
may look like one): The declaration of an object is not an assignment operation, it is just another of the syntaxes to call
single-argument constructors.
The assignment on foo is an assignment operation. No object is being declared here, but an operation is being
performed on an existing object; foo.
The copy assignment operator is an overload of operator= which takes a value or reference of the class itself as
parameter. The return value is generally a reference to *this (although this is not required). For example, for a class
MyClass, the copy assignment may have the following signature:
The copy assignment operator is also a special function and is also defined implicitly if a class has no custom copy nor
move assignments (nor move constructor) defined.
But again, the implicit version performs a shallow copy which is suitable for many classes, but not for classes with
pointers to objects they handle its storage, as is the case in Example5. In this case, not only the class incurs the risk of
deleting the pointed object twice, but the assignment creates memory leaks by not deleting the object pointed by the
object before the assignment. These issues could be solved with a copy assignment that deletes the previous object
and performs a deep copy:
Or even better, since its string member is not constant, it could re-utilize the same string object:
https://www.cplusplus.com/doc/tutorial/classes2/ 3/5
6/3/2021 Special members - C++ Tutorials
Unnamed objects are objects that are temporary in nature, and thus haven't even been given a name. Typical examples
of unnamed objects are return values of functions or type-casts.
Using the value of a temporary object such as these to initialize another object or to assign its value, does not really
require a copy: the object is never going to be used for anything else, and thus, its value can be moved into the
destination object. These cases trigger the move constructor and move assignments:
The move constructor is called when an object is initialized on construction using an unnamed temporary. Likewise, the
move assignment is called when an object is assigned the value of an unnamed temporary:
Both the value returned by fn and the value constructed with MyClass are unnamed temporaries. In these cases, there
is no need to make a copy, because the unnamed object is very short-lived and can be acquired by the other object
when this is a more efficient operation.
The move constructor and move assignment are members that take a parameter of type rvalue reference to the class
itself:
An rvalue reference is specified by following the type with two ampersands (&&). As a parameter, an rvalue reference
matches arguments of temporaries of this type.
The concept of moving is most useful for objects that manage the storage they use, such as objects that allocate
storage with new and delete. In such objects, copying and moving are really different operations:
- Copying from A to B means that new memory is allocated to B and then the entire content of A is copied to this new
memory allocated for B.
- Moving from A to B means that the memory already allocated to A is transferred to B without allocating any new
storage. It involves simply copying the pointer.
For example:
1 // move constructor/assignment foo's content: Example
2 #include <iostream>
3 #include <string>
4 using namespace std;
5
6 class Example6 {
7 string* ptr;
8 public:
9 Example6 (const string& str) : ptr(new string(str)) {}
10 ~Example6 () {delete ptr;}
11 // move constructor
12 Example6 (Example6&& x) : ptr(x.ptr) {x.ptr=nullptr;}
13 // move assignment
14 Example6& operator= (Example6&& x) {
15 delete ptr;
16 ptr = x.ptr;
17 x.ptr=nullptr;
18 return *this;
19 } Edit
20 // access content: &
21 const string& content() const {return *ptr;} Run
22 // addition:
23 Example6 operator+(const Example6& rhs) {
24 return Example6(content()+rhs.content());
25 }
26 };
27
28
29 int main () {
30 Example6 foo ("Exam");
31 Example6 bar = Example6("ple"); // move-construction
32
33 foo = foo + bar; // move-assignment
34
35 cout << "foo's content: " << foo.content() << '\n';
36 return 0;
37 }
Compilers already optimize many cases that formally require a move-construction call in what is known as Return Value
Optimization. Most notably, when the value returned by a function is used to initialize an object. In these cases, the
move constructor may actually never get called.
Note that even though rvalue references can be used for the type of any function parameter, it is seldom useful for uses
other than the move constructor. Rvalue references are tricky, and unnecessary uses may be the source of errors quite
difficult to track.
Implicit members
The six special members functions described above are members implicitly declared on classes under certain
circumstances:
https://www.cplusplus.com/doc/tutorial/classes2/ 4/5
6/3/2021 Special members - C++ Tutorials
Copy constructor if no move constructor and no move assignment copies all members
Copy assignment if no move constructor and no move assignment copies all members
Move constructor if no destructor, no copy constructor and no copy nor move assignment moves all members
Move assignment if no destructor, no copy constructor and no copy nor move assignment moves all members
Notice how not all special member functions are implicitly defined in the same cases. This is mostly due to backwards
compatibility with C structures and earlier C++ versions, and in fact some include deprecated cases. Fortunately, each
class can select explicitly which of these members exist with their default definition or which are deleted by using the
keywords default and delete, respectively. The syntax is either one of:
function_declaration = default;
function_declaration = delete;
For example:
1 // default and delete implicit members bar's area: 200
2 #include <iostream>
3 using namespace std;
4
5 class Rectangle {
6 int width, height;
7 public:
8 Rectangle (int x, int y) : width(x), height(y) {}
9 Rectangle() = default;
10 Rectangle (const Rectangle& other) = delete; Edit
11 int area() {return width*height;} &
12 }; Run
13
14 int main () {
15 Rectangle foo;
16 Rectangle bar (10,20);
17
18 cout << "bar's area: " << bar.area() << '\n';
19 return 0;
20 }
Here, Rectangle can be constructed either with two int arguments or be default-constructed (with no arguments). It
cannot however be copy-constructed from another Rectangle object, because this function has been deleted. Therefore,
assuming the objects of the last example, the following statement would not be valid:
It could, however, be made explicitly valid by defining its copy constructor as:
Note that, the keyword default does not define a member function equal to the default constructor (i.e., where default
constructor means constructor with no parameters), but equal to the constructor that would be implicitly defined if not
deleted.
In general, and for future compatibility, classes that explicitly define one copy/move constructor or one copy/move
assignment but not both, are encouraged to specify either delete or default on the other special member functions
they don't explicitly define.
Previous: Next:
Classes (II) Friendship and inheritance
Index
https://www.cplusplus.com/doc/tutorial/classes2/ 5/5