SlideShare a Scribd company logo
Resource wrappers
Ilio Catallo - info@iliocatallo.it
Outline
β€’ The importance of std::vector
β€’ Representa2on
β€’ Ini2aliza2on
β€’ Accessing elements
β€’ Destruc2on
Outline
β€’ Copying
β€’ Assignment
β€’ Rule of three
β€’ Bibliography
The importance of
std::vector
The ubiquity of std::vector
The most useful container in the C++ standard library is
std::vector
Why std::vector is so useful
std::vector is built from low-level memory management
facili5es, such as pointers and arrays
Why std::vector is so useful
std::vector's primary role is to help us avoid the complexi4es of
those facili4es
Why std::vector is so useful
That is, std::vector is designed to insulate us from some of the
unpleasant aspects of real memory
Building std::vector
In the remainder, we will write a simplified std::vector
implementa0on
Building std::vector
Namely, we will write a non-resizable version of std::vector for
the limited case of int elements
The vector_int class
We will refer to this type as vector_int
Why bother re-inven.ng the wheel when we already have
std::vector?
But why?
The reason is that re-implemen0ng std::vector allows us to
prac0ce many basic language facili0es at once
β€’ Pointers & arrays
β€’ Classes & operator overloading
But why?
Secondly, it allows stressing that whenever we design a class, we
must consider ini#aliza#on, copying and destruc#on1
1
For simplicity, in the remainder we are going to deliberately ignore move seman8cs, i.e., we are going to discuss
object lifecycle as of C++03
But why?
Finally, as computer scien2sts we need to know how to design and
implement abstrac2ons such as std::vector
Objec&ves
Ideally, we would like to achieve the following:
void f() {
vector_int v(7); // varying number of elements
v[0] = 7; // writing elements
std::cout << v.size(); // it knows its size
std::cout << v[1]; // values are default initialized
vector_int w = v; // copy construction
vector_int u; u = v; // assignment
// automatic memory management
// (no delete[] required)
}
Natural behavior
vector_int provides us opera,ons that seem natural from the
viewpoint of a user, rather than from the viewpoint of hardware
Natural behavior
We want to get to the point where we can program using types
that provide exactly the proper4es we want based on logical needs
Natural behavior
To get there, we have to overcome a number of fundamental
constraints related to access to the bare machine, such as:
β€’ An object in memory is of fixed size
β€’ An object in memory is in one specific place
Representa)on
Designing vector_int
We start our incremental design of vector_int by considering a
very simple use:
vector_int grades(4);
grades[0] = 28;
grades[1] = 27;
grades[2] = 30:
grades[3] = 25;
Designing vector_int
This creates a vector_int with four elements and give those
elements the values 28, 27, 30, 25
vector_int grades(4);
grades[0] = 28;
grades[1] = 27;
grades[2] = 30:
grades[3] = 25;
The size of a vector_int
The number of elements of a vector_int is called its size
vector_int grades(4);
grades[0] = 28;
grades[1] = 27;
grades[2] = 30:
grades[3] = 25;
The size of a vector_int
Therefore, the size of grades is four
vector_int grades(4);
grades[0] = 28;
grades[1] = 27;
grades[2] = 30:
grades[3] = 25;
The size of a vector_int
Moreover, the number of elements of a vector_int are indexed
from 0 to size - 1
vector_int grades(4);
grades[0] = 28;
grades[1] = 27;
grades[2] = 30:
grades[3] = 25;
Represen'ng grades
Graphically, we can represent grades like:
grades[0] grades[1] grades[2] grades[3]
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”‚
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
grades: β”‚ 4 β”‚ β”‚
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
How do we implement that drawing in code?
vector_int is a class
Unsurprisingly, we have to define a class and call it vector_int
class vector_int {
...
};
Data members
Obviously, we cannot design vector_int to have a fixed number
of elements
class vector_int {
public:
...
private:
int elem0, elem1, elem2, elem3;
};
Data members
Conversely, we need a data member that points to the sequence of
elements
class vector_int {
public:
...
private:
int* elem;
};
Data members
That is, we need a pointer member to the sequence of elements
class vector_int {
public:
...
private:
int* elem;
};
Data members
Furthermore, we need a data member to hold the size of the
sequence
class vector_int {
public:
...
private:
std::size_t sz;
int* elem;
};
grades representa)on
Therefore, a refined grades representa0on is as follows:
elem[0] elem[1] elem[2] elem[3]
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚ β”‚ β”‚ int[4]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
grades: β”‚ 4 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
Ini$aliza$on
Ini$aliza$on
At construc*on *me, we would like to allocate sufficient space for
the elements on the heap
// v allocates 4 ints on the heap
vector_int v(4);
Ini$aliza$on
Elements will be later accessed through the data member v.elem
class vector_int {
public:
...
private:
std::size_t sz;
int* elem;
};
Alloca&ng space
To this end, we use new in the constructor to allocate space for the
elements, and we let elem point to the address returned by new
class vector_int {
public:
vector_int(std::size_t sz): elem(...) {}
...
}
Alloca&ng space
To this end, we use new in the constructor to allocate space for the
elements, and we let elem point to the address returned by new
class vector_int {
public:
vector_int(std::size_t sz): elem(new int[sz]) {}
...
}
Storing the size
Moreover, since there is no way to recover the size of the dynamic
array from elem, we store it in sz
class vector_int {
public:
vector_int(std::size_t sz): sz(sz),
elem(new int[sz]) {}
...
};
Storing the size
We want users of vector_int to be able to get the number of
elements
size() access func)on
Hence, we provide an access func2on size() that returns the
number of elements
class vector_int {
public:
vector_int(std::size_t sz): sz(sz),
elem(new int[sz]) {}
std::size_t size() const { return sz; }
private:
std::size_t sz;
int* elem;
};
Sensible ini)aliza)on
In addi'on, we would like to ini'alize the newly-allocated elements
to a sensible value
vector_int v(3);
std::cout << v[0]; // output: 0 (as opposed to some random values)
Sensible ini)aliza)on
Again, we can do that at construc2on 2me
vector_int v(3);
std::cout << v[0]; // output: 0 (as opposed to some random values)
Sensible ini)aliza)on
class vector_int {
public:
vector_int(std::size_t sz): sz(sz),
elem(new int[sz]) {
for (std::size_t i = 0; i < sz; ++i)
elem[i] = 0;
}
std::size_t size() const { return sz; }
private:
std::size_t sz;
int* elem;
};
Default constructor
Moreover, in the case of containers, we have a natural default valid
state, i.e., the empty container
Default constructor
Hence, we can introduce a default constructor
class vector_int {
public:
vector_int(): sz(0), elem(nullptr) {}
vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...}
private:
std::size_t sz;
int* elem;
};
Accessing elements
vector_int as a pointer
Note that – up to this point – vector_int values are just pointers
that remember the size of the pointed array
vector_int v(4);
std::cout << v.size(); // output: 4
Accessing elements
However, for a vector_int to be usable, we need a way to read
and write elements
vector_int v(4);
v[0] = 1; // writing elements
std::cout << v[0]; // reading elements
Accessing elements
That is, we would like to add the possibility of access elements
through our usual subscript nota-on
vector_int v(4);
v[0] = 1; // writing elements
std::cout << v[0]; // reading elements
Operator func-on
The way to get that is to define a member operator func,on
operator[]
vector_int v(4);
v[0] = 1; // writing elements
std::cout << v[0]; // reading elements
Defining operator[]
How can we define the operator[] overload?
class vector_int {
public:
...
??? operator[](std::size_t i) { ??? }
private:
std::size_t sz;
int* elem;
};
Defining operator[]
Intui&vely, one would say
class vector_int {
public:
...
int operator[](std::size_t i) { return elem[i]; }
private:
std::size_t sz;
int* elem;
};
Defining operator[]
Apparently, we can now manipulate elements in a vector_int
vector_int v(10);
int x = v[2];
std::cout << x; // output: 0
Naive implementa,on
This looks good and simple, but unfortunately it is too simple
int operator[](std::size_t i) { return elem[i]; }
Naive implementa,on
What happens when we write the following?
vector_int v(10);
v[3] = 7;
Naive implementa,on
We get a compile-)me error :-(
vector_int v(10);
v[3] = 7; // compile-time error!
Returning a value
Our implementa-on of operator[] returns a temporary of type
int. Hence, we cannot assign any addi-onal value to it
vector_int v(10);
v[3] = 7;
Returning a value
That is, le+ng the subscript operator return a value enables
reading but not wri6ng elements
int operator[](std::size_t i) { return elem[i]; }
Returning a reference
Returning a reference, rather than a value, from the subscript
operator solves this problem
int& operator[](std::size_t i) { return elem[i]; }
Returning a reference
class vector_int {
public:
...
int& operator[](std::size_t i) { return elem[i]; }
private:
std::size_t sz;
int* elem;
};
Constant vector_ints
Our subscript operator has s/ll a problem, namely, it cannot be
invoked for constant vector_ints
void p(vector_int const& v) {
int x = v[0];
}
Constant vector_ints
This is because operator[] has not been marked as const
void p(vector_int const& v) {
int x = v[0];
}
Constant vector_ints
However, we cannot simply mark operator[] as const, as it will
prevent any further modifica9on to its elements
void p(vector_int const& v) {
int x = v[0];
}
Const-overload
To solve this, we provide an addi$onal overload of operator[]
specifically meant for accessing const vectors
class vector_int {
public:
...
int& operator[](std::size_t i) { return elem[i]; }
int operator[](std::size_t i) const { return elem[i]; }
private:
std::size_t sz;
int* elem;
};
Const-overload
We can now access elements of constant vector_ints without
preven4ng the possibility of modifying non-const vector_ints
class vector_int {
public:
...
int& operator[](std::size_t i) { return elem[i]; }
int operator[](std::size_t i) const { return elem[i]; }
private:
std::size_t sz;
int* elem;
};
Destructor
Resource acquisi,on
No#ce that in the constructor we allocate memory for the elements
using new
class vector_int {
public:
vector_int(std::size_t sz): sz(sz),
elem(new int[sz]) {}
...
};
Memory leak
However, when leaving f(), the heap-allocated elements pointed
to by v.elem are not released
void f() {
vector_int v(10);
int e = v[0];
};
Memory leak
We are therefore causing a memory leak
void f() {
vector_int v(10);
int e = v[0];
};
Fixing the leak
To solve this, we must make sure that this memory is freed using
delete[]
void f() {
vector_int v(10);
int e = v[0];
// we should call delete[] before
// returning from f()
};
The clean_up() member
We could define a clean_up() member func0on
class vector_int {
public:
vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...}
void clean_up() { delete[] elem; }
...
private:
std::size_t sz;
int* elem;
};
The clean_up() member
We can then call clean_up() as follows
void f() {
vector_int v(10);
int e = v[0];
v.clean_up();
};
Releasing the memory
Although that would work, one of the most common problems with
the heap is that it is extremely easy to forget to call delete
void f() {
vector_int v(10);
int e = v[0];
v.clean_up();
};
Releasing the memory
The equivalent problem would arise for clean_up()
void f() {
vector_int v(10);
int e = v[0];
v.clean_up();
};
Destructors
Fortunately, C++ provides facili6es that allow us to do be:er than
that
Destructors
In par'cular, in C++ each class is provided with a special func,on
that makes sure that an object is properly cleaned up before it is
destroyed
Destructors
Such a special func.on is called the destructor
Destructors
The destructor is a public member func-ons with no input
parameters and no return type
class vector_int {
public:
~vector_int() {...}
...
};
Destructors
The destructor has the same name as the class, but with a !lde (~)
in front of it
class vector_int {
public:
~vector_int() {...}
...
};
Implemen'ng ~vector_int()
class vector_int {
public:
vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...}
~vector_int() { ??? }
...
private:
std::size_t sz;
int* elem;
};
Implemen'ng ~vector_int()
class vector_int {
public:
vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...}
~vector_int() { delete[] elem; }
...
private:
std::size_t sz;
int* elem;
};
Automa'c memory dealloca'on
Thanks to the presence of the destructor, we do not need to
explicitly release memory
void f() {
vector_int v(10);
int e = v[0];
// Hurray! the dynamic arrays pointed to
// by v.elem is automatically deleted
};
Automa'c memory dealloca'on
The tremendous advantage is that a vector cannot forget to call its
destructor to deallocate the memory used for its elements
Synthesized destructors
If we do not explicitly provide a destructor, the compiler will
generate a synthesized destructor
Synthesized destructors
Such a synthesized destructor invokes the destructors for the
elements (if they have destructors)
vector_int synth. destructor
Since sz and elem do not provide a destructor, the synthesized
destructor would simply reduce to an empty func8on
class vector_int {
public:
// synthesized destructor
~vector_int() {}
...
private:
std::size_t sz;
int* elem;
};
vector_int synth. destructor
This is why we end up with a memory leak if we do not explicitly
specify a destructor for vector_int
class vector_int {
public:
// synthesized destructor
~vector_int() {}
...
private:
std::size_t sz;
int* elem;
};
Copying
Copying two vector_ints
Let us try to copy one vector_int into another
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v; // what happens?
}
Copying two vector_ints
Ideally we would like w to become a copy of v
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v; // what happens?
}
Copy seman+cs
That means:
β€’ w.size() == v.size()
β€’ w[i] == v[i] for all i's in [0:v.size())
β€’ &w[i] != &v[i] for all i's in [0:v.size())
Copy seman+cs
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
v: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
w: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
β”‚
└──────────┐
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Copy seman+cs
Furthermore, we want all memory to be released once returning
from h()
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
// here, v.elem and w.elem get released
}
Wrong copy behavior
Unfortunately, this is not what happens with our vector_int
implementa4on
Copying is ini*alizing
First, note that w is ini#alized from v
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
}
Copying is ini*alizing
We know that ini#aliza#on is done by a constructor
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
}
Copying is ini*alizing
Hence, we have to conclude that vector_int provides a
constructor that accepts vector_ints as its only input argument
vector_int(vector_int const& v) {...}
Copying is ini*alizing
This is made even more evident if we use an equivalent nota4on
for the last line in h()
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w(v); // the same as: vector_int w = v;
}
Copying is ini*alizing
However, we never wrote such a constructor
Copy constructor
It turns out that every class in C++ is provided with a special
constructor called copy constructor
vector_int(vector_int const& v) {...}
Copy constructor
A copy constructor is defined to take as its argument a constant
reference to the object from which to copy
vector_int(vector_int const& v) {...}
vector_int's constructors
class vector_int {
public:
vector_int(): sz(0), elem(nullptr) {}
vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...}
vector_int(vector_int const& v) { ... }
private:
std::size_t sz;
int* elem;
};
Const-reference
Note that the v is passed by reference
vector_int(vector_int const& v) {...}
Const-reference
Why don't we pass v by value?
vector_int(vector_int const& v) {...}
Const-reference
Passing by value would require v to be copied...
vector_int(vector_int const& v) {...}
Const-reference
...which would in turn cause the invoca2on of v's copy
constructor...
vector_int(vector_int const& v) {...}
Const-reference
...thus leading to an infinite loop!
vector_int(vector_int const& v) {...}
Synthesized copy constructor
If we do not provide an explicit copy constructor, the compiler will
generate a synthesized one for us
Synthesized copy constructor
Synthesized copy constructors simply perform memberwise copy
class vector_int {
public:
// synthesized copy constructor
vector_int(vector_int const& v): sz(v.sz),
elem(v.elem) {}
...
private:
std::size_t sz;
int* elem;
};
Copying pointers
However, memberwise copying in the presence of pointer
members (such as elem) usually causes problems
// synthesized copy constructor
vector_int(vector_int const& v): sz(v.sz),
elem(v.elem) {}
Copying pointers
Specifically, w ends up sharing v's elements
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
}
Sharing elements
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
w: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
β”‚
└──────────┐
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
v: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
Sharing elements
What is the output?
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
w[0] = 10;
std::cout << v[0];
Sharing elements
What is the output?
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
w[0] = 10;
std::cout << v[0]; // output: 10
Double dele)on
Moreover, when we return from h() the destructors for v and w
are implicitly called
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
}
Double dele)on
Due to their hidden connec-on, both v and w will try to release the
same memory area
A working copy constructor
Hence, we need to explicitly provide a copy constructor that will
1. set the number of elements (i.e., the size)
2. allocate memory for its elements
3. copying the elements from the source vector_int
A working copy constructor
class vector_int {
public:
vector_int(vector_int const& v): sz(v.sz),
elem(new int[v.sz]) {
std::copy(v.elem, v.elem + sz, elem);
}
...
private:
std::size_t sz;
int* elem;
};
A working copy constructor
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
}
A working copy constructor
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
v: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
w: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
β”‚
└──────────┐
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
No more double dele+on
Given that the two vector_ints are now independent, the two
destructors can do the right thing
void h() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w = v;
}
Assignment
Assignment
Even though we now correctly handle copy construc4on,
vector_ints can s4ll be copied by assignment
void g() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w(4); w = v;
}
Assignment
What happens when we execute the following?
void g() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w(4); w = v; // what happens?
}
Memory leak and double dele/on
Unfortunately, we once again end up with a memory leak and a
double dele-on
void g() {
vector_int v(3);
v[0] = 7;
v[1] = 3;
v[2] = 8;
vector_int w(4); w = v;
}
Synthesized assignment operator
As a ma&er of fact, if we do not provide any overload for the
assignment operator, the compiler will synthesize one for us
Synthesized assignment operator
Synth. assignment operators perform memberwise assignment
class vector_int {
public:
// synthesized assignment operator
vector_int& operator=(vector_int const& v) {
sz = v.sz;
elem = v.elem;
return *this;
}
...
private:
std::size_t sz;
int* elem;
};
Synthesized assignment operator
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 0 β”‚ 0 β”‚ 0 β”‚ 0 β”‚ int[4]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”‚
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
w: β”‚ 4 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
v: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
Synthesized assignment operator
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 0 β”‚ 0 β”‚ 0 β”‚ 0 β”‚ int[4]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
w: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
β”‚
└──────────┐
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3]
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
sz elem
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
v: β”‚ 3 β”‚ β”‚ vector_int
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
Synth. assignment for vector_int
Since we did not provide an explicit overload for operator=, the
synthesized assignment is used
vector_int& operator=(vector_int const& v) {...}
Working assignment operator
The remedy for the assignment is fundamentally the same as for
the copy constructor
vector_int& operator=(vector_int const& v) {...}
Working assignment operator
class vector_int {
public:
vector_int& operator=(vector_int const& v) {
int* p = new int[v.sz];
std::copy(v.elem, v.elem + v.sz, p);
delete[] elem;
elem = p;
sz = v.sz;
return *this;
}
...
private:
std::size_t sz;
int* elem;
};
Rule of three
Destructors are fundamental
Destructors are conceptually simple but are the founda'on for
many of the most effec5ve C++ programming techniques
Destructors are fundamental
The usage of the constructor / destructor pair for correctly
managing heap-allocated memory is the archetypical example
Resource wrappers need destructors
More generally, a class needs a destructor if it acquires resources
Resource
A resource is something we get from somewhere and that we must
give back once we have finished using it
β€’ Memory
β€’ File descriptor
β€’ Socket
β€’ ...
The big three
A class that needs a destructor almost always needs a copy
construc-on and assignment
The big three
The reason is that if an object has acquired a resource the default
meaning of copy is almost certainly wrong
The rule of three
This is summarised in the so-called rule of three2
If you need to explicitly declare either the destructor, copy constructor
or assignment operator yourself, you probably need to explicitly declare
all three of them
2
Once again, we are limi/ng ourselves to C++03, in C++11 one would obey either the rule of five or the rule of zero
Bibliography
Bibliography
β€’ B. Stroustrup, The C++ Programming Language (4th
ed.)
β€’ B, Stroustrup, Programming: Principles and Prac@ce
Using C++ (2nd
ed.)
β€’ A. Stepanov, Notes on programming
β€’ StackOverflow FAQ, What is the rule of three?

More Related Content

What's hot

Chap 5 c++
Chap 5 c++Chap 5 c++
Chap 5 c++
Venkateswarlu Vuggam
Β 
Chap 6 c++
Chap 6 c++Chap 6 c++
Chap 6 c++
Venkateswarlu Vuggam
Β 
Ch7 structures
Ch7 structuresCh7 structures
Ch7 structuresHattori Sidek
Β 
Chap 6 c++
Chap 6 c++Chap 6 c++
Chap 6 c++
Venkateswarlu Vuggam
Β 
02. Data Types and variables
02. Data Types and variables02. Data Types and variables
02. Data Types and variables
Intro C# Book
Β 
C++ Language
C++ LanguageC++ Language
C++ Language
Syed Zaid Irshad
Β 
Pointers in C
Pointers in CPointers in C
Pointers in Cguestdc3f16
Β 
02. Primitive Data Types and Variables
02. Primitive Data Types and Variables02. Primitive Data Types and Variables
02. Primitive Data Types and Variables
Intro C# Book
Β 
Chap 5 c++
Chap 5 c++Chap 5 c++
Chap 5 c++
Venkateswarlu Vuggam
Β 
2.overview of c++ ________lecture2
2.overview of c++  ________lecture22.overview of c++  ________lecture2
2.overview of c++ ________lecture2
Warui Maina
Β 
Arrays
ArraysArrays
Arrays
archikabhatia
Β 
C Prog - Pointers
C Prog - PointersC Prog - Pointers
C Prog - Pointersvinay arora
Β 
13. Java text processing
13.  Java text processing13.  Java text processing
13. Java text processing
Intro C# Book
Β 
Computer Programming- Lecture 7
Computer Programming- Lecture 7Computer Programming- Lecture 7
Computer Programming- Lecture 7
Dr. Md. Shohel Sayeed
Β 
46630497 fun-pointer-1
46630497 fun-pointer-146630497 fun-pointer-1
46630497 fun-pointer-1
AmIt Prasad
Β 
Array&amp;string
Array&amp;stringArray&amp;string
Array&amp;string
chanchal ghosh
Β 
19. Data Structures and Algorithm Complexity
19. Data Structures and Algorithm Complexity19. Data Structures and Algorithm Complexity
19. Data Structures and Algorithm Complexity
Intro C# Book
Β 
Pointers+(2)
Pointers+(2)Pointers+(2)
Pointers+(2)Rubal Bansal
Β 
Java Foundations: Strings and Text Processing
Java Foundations: Strings and Text ProcessingJava Foundations: Strings and Text Processing
Java Foundations: Strings and Text Processing
Svetlin Nakov
Β 
Chap 4 c++
Chap 4 c++Chap 4 c++
Chap 4 c++
Venkateswarlu Vuggam
Β 

What's hot (20)

Chap 5 c++
Chap 5 c++Chap 5 c++
Chap 5 c++
Β 
Chap 6 c++
Chap 6 c++Chap 6 c++
Chap 6 c++
Β 
Ch7 structures
Ch7 structuresCh7 structures
Ch7 structures
Β 
Chap 6 c++
Chap 6 c++Chap 6 c++
Chap 6 c++
Β 
02. Data Types and variables
02. Data Types and variables02. Data Types and variables
02. Data Types and variables
Β 
C++ Language
C++ LanguageC++ Language
C++ Language
Β 
Pointers in C
Pointers in CPointers in C
Pointers in C
Β 
02. Primitive Data Types and Variables
02. Primitive Data Types and Variables02. Primitive Data Types and Variables
02. Primitive Data Types and Variables
Β 
Chap 5 c++
Chap 5 c++Chap 5 c++
Chap 5 c++
Β 
2.overview of c++ ________lecture2
2.overview of c++  ________lecture22.overview of c++  ________lecture2
2.overview of c++ ________lecture2
Β 
Arrays
ArraysArrays
Arrays
Β 
C Prog - Pointers
C Prog - PointersC Prog - Pointers
C Prog - Pointers
Β 
13. Java text processing
13.  Java text processing13.  Java text processing
13. Java text processing
Β 
Computer Programming- Lecture 7
Computer Programming- Lecture 7Computer Programming- Lecture 7
Computer Programming- Lecture 7
Β 
46630497 fun-pointer-1
46630497 fun-pointer-146630497 fun-pointer-1
46630497 fun-pointer-1
Β 
Array&amp;string
Array&amp;stringArray&amp;string
Array&amp;string
Β 
19. Data Structures and Algorithm Complexity
19. Data Structures and Algorithm Complexity19. Data Structures and Algorithm Complexity
19. Data Structures and Algorithm Complexity
Β 
Pointers+(2)
Pointers+(2)Pointers+(2)
Pointers+(2)
Β 
Java Foundations: Strings and Text Processing
Java Foundations: Strings and Text ProcessingJava Foundations: Strings and Text Processing
Java Foundations: Strings and Text Processing
Β 
Chap 4 c++
Chap 4 c++Chap 4 c++
Chap 4 c++
Β 

Viewers also liked

Ays Summer Meet the Stars
Ays Summer Meet the StarsAys Summer Meet the Stars
Ays Summer Meet the Stars
AysSummer
Β 
Partnering with communities in Colorado
Partnering with communities in ColoradoPartnering with communities in Colorado
Partnering with communities in Colorado
Donald Nease
Β 
Business health check business infoload 2016
Business health check   business infoload 2016Business health check   business infoload 2016
Business health check business infoload 2016
Infoload
Β 
JSpiders - Wrapper classes
JSpiders - Wrapper classesJSpiders - Wrapper classes
JSpiders - Wrapper classes
JSpiders Basavanagudi
Β 
Are you keen to know about upcoming trends in Live Event Industry
Are you keen to know about upcoming trends in Live Event IndustryAre you keen to know about upcoming trends in Live Event Industry
Are you keen to know about upcoming trends in Live Event Industry
Priyadarshani Jain
Β 
Operator overloading in C++
Operator overloading in C++Operator overloading in C++
Operator overloading in C++
Ilio Catallo
Β 
Regular types in C++
Regular types in C++Regular types in C++
Regular types in C++
Ilio Catallo
Β 
C++ 11 range-based for loop
C++ 11   range-based for loopC++ 11   range-based for loop
C++ 11 range-based for loop
mohamed sikander
Β 
C++ Standard Template Library
C++ Standard Template LibraryC++ Standard Template Library
C++ Standard Template Library
Ilio Catallo
Β 

Viewers also liked (9)

Ays Summer Meet the Stars
Ays Summer Meet the StarsAys Summer Meet the Stars
Ays Summer Meet the Stars
Β 
Partnering with communities in Colorado
Partnering with communities in ColoradoPartnering with communities in Colorado
Partnering with communities in Colorado
Β 
Business health check business infoload 2016
Business health check   business infoload 2016Business health check   business infoload 2016
Business health check business infoload 2016
Β 
JSpiders - Wrapper classes
JSpiders - Wrapper classesJSpiders - Wrapper classes
JSpiders - Wrapper classes
Β 
Are you keen to know about upcoming trends in Live Event Industry
Are you keen to know about upcoming trends in Live Event IndustryAre you keen to know about upcoming trends in Live Event Industry
Are you keen to know about upcoming trends in Live Event Industry
Β 
Operator overloading in C++
Operator overloading in C++Operator overloading in C++
Operator overloading in C++
Β 
Regular types in C++
Regular types in C++Regular types in C++
Regular types in C++
Β 
C++ 11 range-based for loop
C++ 11   range-based for loopC++ 11   range-based for loop
C++ 11 range-based for loop
Β 
C++ Standard Template Library
C++ Standard Template LibraryC++ Standard Template Library
C++ Standard Template Library
Β 

Similar to Resource wrappers in C++

cpp programing language exercise Vector.ppt
cpp programing language exercise Vector.pptcpp programing language exercise Vector.ppt
cpp programing language exercise Vector.ppt
ssuser8ac8e7
Β 
Oops lab manual2
Oops lab manual2Oops lab manual2
Oops lab manual2
Mouna Guru
Β 
Vector class in C++
Vector class in C++Vector class in C++
Vector class in C++
Jawad Khan
Β 
Vector3
Vector3Vector3
Vector3
Rajendran
Β 
What's New in C++ 11/14?
What's New in C++ 11/14?What's New in C++ 11/14?
What's New in C++ 11/14?
Dina Goldshtein
Β 
Intro To C++ - Class #18: Vectors & Arrays
Intro To C++ - Class #18: Vectors & ArraysIntro To C++ - Class #18: Vectors & Arrays
Intro To C++ - Class #18: Vectors & Arrays
Blue Elephant Consulting
Β 
I am trying to fill out a program where the method definitions will b.docx
I am trying  to fill out a program where the method definitions will b.docxI am trying  to fill out a program where the method definitions will b.docx
I am trying to fill out a program where the method definitions will b.docx
Phil4IDBrownh
Β 
Vectors Intro.ppt
Vectors Intro.pptVectors Intro.ppt
Vectors Intro.ppt
puneet680917
Β 
Chapter1.pptx
Chapter1.pptxChapter1.pptx
Chapter1.pptx
WondimuBantihun1
Β 
c_tutorial_2.ppt
c_tutorial_2.pptc_tutorial_2.ppt
c_tutorial_2.ppt
gitesh_nagar
Β 
C Programming - Refresher - Part III
C Programming - Refresher - Part IIIC Programming - Refresher - Part III
C Programming - Refresher - Part III
Emertxe Information Technologies Pvt Ltd
Β 
C++ references
C++ referencesC++ references
C++ references
corehard_by
Β 
CLASSES, STRUCTURE,UNION in C++
CLASSES, STRUCTURE,UNION in C++CLASSES, STRUCTURE,UNION in C++
CLASSES, STRUCTURE,UNION in C++
Prof Ansari
Β 
02.adt
02.adt02.adt
02.adt
Aditya Asmara
Β 
Arrays, Structures And Enums
Arrays, Structures And EnumsArrays, Structures And Enums
Arrays, Structures And Enums
Bhushan Mulmule
Β 
Lecture 2 java.pdf
Lecture 2 java.pdfLecture 2 java.pdf
Lecture 2 java.pdf
SantoshSurwade2
Β 
OOP program questions with answers
OOP program questions with answersOOP program questions with answers
OOP program questions with answers
Quratulain Naqvi
Β 
The deadline of submission is February 15th. Acceptable file format f.pdf
The deadline of submission is February 15th. Acceptable file format f.pdfThe deadline of submission is February 15th. Acceptable file format f.pdf
The deadline of submission is February 15th. Acceptable file format f.pdf
fashionfootwear1
Β 
Class and object C++.pptx
Class and object C++.pptxClass and object C++.pptx
Class and object C++.pptx
SantoshVarshney3
Β 

Similar to Resource wrappers in C++ (20)

cpp programing language exercise Vector.ppt
cpp programing language exercise Vector.pptcpp programing language exercise Vector.ppt
cpp programing language exercise Vector.ppt
Β 
Oops lab manual2
Oops lab manual2Oops lab manual2
Oops lab manual2
Β 
Vector class in C++
Vector class in C++Vector class in C++
Vector class in C++
Β 
Op ps
Op psOp ps
Op ps
Β 
Vector3
Vector3Vector3
Vector3
Β 
What's New in C++ 11/14?
What's New in C++ 11/14?What's New in C++ 11/14?
What's New in C++ 11/14?
Β 
Intro To C++ - Class #18: Vectors & Arrays
Intro To C++ - Class #18: Vectors & ArraysIntro To C++ - Class #18: Vectors & Arrays
Intro To C++ - Class #18: Vectors & Arrays
Β 
I am trying to fill out a program where the method definitions will b.docx
I am trying  to fill out a program where the method definitions will b.docxI am trying  to fill out a program where the method definitions will b.docx
I am trying to fill out a program where the method definitions will b.docx
Β 
Vectors Intro.ppt
Vectors Intro.pptVectors Intro.ppt
Vectors Intro.ppt
Β 
Chapter1.pptx
Chapter1.pptxChapter1.pptx
Chapter1.pptx
Β 
c_tutorial_2.ppt
c_tutorial_2.pptc_tutorial_2.ppt
c_tutorial_2.ppt
Β 
C Programming - Refresher - Part III
C Programming - Refresher - Part IIIC Programming - Refresher - Part III
C Programming - Refresher - Part III
Β 
C++ references
C++ referencesC++ references
C++ references
Β 
CLASSES, STRUCTURE,UNION in C++
CLASSES, STRUCTURE,UNION in C++CLASSES, STRUCTURE,UNION in C++
CLASSES, STRUCTURE,UNION in C++
Β 
02.adt
02.adt02.adt
02.adt
Β 
Arrays, Structures And Enums
Arrays, Structures And EnumsArrays, Structures And Enums
Arrays, Structures And Enums
Β 
Lecture 2 java.pdf
Lecture 2 java.pdfLecture 2 java.pdf
Lecture 2 java.pdf
Β 
OOP program questions with answers
OOP program questions with answersOOP program questions with answers
OOP program questions with answers
Β 
The deadline of submission is February 15th. Acceptable file format f.pdf
The deadline of submission is February 15th. Acceptable file format f.pdfThe deadline of submission is February 15th. Acceptable file format f.pdf
The deadline of submission is February 15th. Acceptable file format f.pdf
Β 
Class and object C++.pptx
Class and object C++.pptxClass and object C++.pptx
Class and object C++.pptx
Β 

More from Ilio Catallo

Memory management in C++
Memory management in C++Memory management in C++
Memory management in C++
Ilio Catallo
Β 
Spring MVC - Wiring the different layers
Spring MVC -  Wiring the different layersSpring MVC -  Wiring the different layers
Spring MVC - Wiring the different layers
Ilio Catallo
Β 
Java and Java platforms
Java and Java platformsJava and Java platforms
Java and Java platforms
Ilio Catallo
Β 
Spring MVC - Web Forms
Spring MVC  - Web FormsSpring MVC  - Web Forms
Spring MVC - Web Forms
Ilio Catallo
Β 
Spring MVC - The Basics
Spring MVC -  The BasicsSpring MVC -  The Basics
Spring MVC - The Basics
Ilio Catallo
Β 
Web application architecture
Web application architectureWeb application architecture
Web application architecture
Ilio Catallo
Β 
Introduction To Spring
Introduction To SpringIntroduction To Spring
Introduction To Spring
Ilio Catallo
Β 
Gestione della memoria in C++
Gestione della memoria in C++Gestione della memoria in C++
Gestione della memoria in C++
Ilio Catallo
Β 
Array in C++
Array in C++Array in C++
Array in C++
Ilio Catallo
Β 
Puntatori e Riferimenti
Puntatori e RiferimentiPuntatori e Riferimenti
Puntatori e Riferimenti
Ilio Catallo
Β 
Java Persistence API
Java Persistence APIJava Persistence API
Java Persistence API
Ilio Catallo
Β 
JSP Standard Tag Library
JSP Standard Tag LibraryJSP Standard Tag Library
JSP Standard Tag Library
Ilio Catallo
Β 
Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3
Ilio Catallo
Β 
Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3
Ilio Catallo
Β 
Introduction to Struts 1.3
Introduction to Struts 1.3Introduction to Struts 1.3
Introduction to Struts 1.3
Ilio Catallo
Β 
Community Detection
Community DetectionCommunity Detection
Community DetectionIlio Catallo
Β 
WWW12 - The CUbRIK Project
WWW12 - The CUbRIK ProjectWWW12 - The CUbRIK Project
WWW12 - The CUbRIK ProjectIlio Catallo
Β 

More from Ilio Catallo (17)

Memory management in C++
Memory management in C++Memory management in C++
Memory management in C++
Β 
Spring MVC - Wiring the different layers
Spring MVC -  Wiring the different layersSpring MVC -  Wiring the different layers
Spring MVC - Wiring the different layers
Β 
Java and Java platforms
Java and Java platformsJava and Java platforms
Java and Java platforms
Β 
Spring MVC - Web Forms
Spring MVC  - Web FormsSpring MVC  - Web Forms
Spring MVC - Web Forms
Β 
Spring MVC - The Basics
Spring MVC -  The BasicsSpring MVC -  The Basics
Spring MVC - The Basics
Β 
Web application architecture
Web application architectureWeb application architecture
Web application architecture
Β 
Introduction To Spring
Introduction To SpringIntroduction To Spring
Introduction To Spring
Β 
Gestione della memoria in C++
Gestione della memoria in C++Gestione della memoria in C++
Gestione della memoria in C++
Β 
Array in C++
Array in C++Array in C++
Array in C++
Β 
Puntatori e Riferimenti
Puntatori e RiferimentiPuntatori e Riferimenti
Puntatori e Riferimenti
Β 
Java Persistence API
Java Persistence APIJava Persistence API
Java Persistence API
Β 
JSP Standard Tag Library
JSP Standard Tag LibraryJSP Standard Tag Library
JSP Standard Tag Library
Β 
Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3
Β 
Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3
Β 
Introduction to Struts 1.3
Introduction to Struts 1.3Introduction to Struts 1.3
Introduction to Struts 1.3
Β 
Community Detection
Community DetectionCommunity Detection
Community Detection
Β 
WWW12 - The CUbRIK Project
WWW12 - The CUbRIK ProjectWWW12 - The CUbRIK Project
WWW12 - The CUbRIK Project
Β 

Recently uploaded

The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
Β 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
Β 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
Β 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
Β 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
Vlad Stirbu
Β 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
Β 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
Β 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
Β 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
Β 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
Β 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
Β 
The Metaverse and AI: how can decision-makers harness the Metaverse for their...
The Metaverse and AI: how can decision-makers harness the Metaverse for their...The Metaverse and AI: how can decision-makers harness the Metaverse for their...
The Metaverse and AI: how can decision-makers harness the Metaverse for their...
Jen Stirrup
Β 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Aggregage
Β 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
Β 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
Β 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
Β 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
RinaMondal9
Β 
UiPath Community Day Dubai: AI at Work..
UiPath Community Day Dubai: AI at Work..UiPath Community Day Dubai: AI at Work..
UiPath Community Day Dubai: AI at Work..
UiPathCommunity
Β 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
nkrafacyberclub
Β 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
Β 

Recently uploaded (20)

The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Β 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Β 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Β 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Β 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
Β 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
Β 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Β 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
Β 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
Β 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
Β 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Β 
The Metaverse and AI: how can decision-makers harness the Metaverse for their...
The Metaverse and AI: how can decision-makers harness the Metaverse for their...The Metaverse and AI: how can decision-makers harness the Metaverse for their...
The Metaverse and AI: how can decision-makers harness the Metaverse for their...
Β 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Β 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
Β 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Β 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Β 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
Β 
UiPath Community Day Dubai: AI at Work..
UiPath Community Day Dubai: AI at Work..UiPath Community Day Dubai: AI at Work..
UiPath Community Day Dubai: AI at Work..
Β 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Β 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
Β 

Resource wrappers in C++

  • 1. Resource wrappers Ilio Catallo - info@iliocatallo.it
  • 2. Outline β€’ The importance of std::vector β€’ Representa2on β€’ Ini2aliza2on β€’ Accessing elements β€’ Destruc2on
  • 3. Outline β€’ Copying β€’ Assignment β€’ Rule of three β€’ Bibliography
  • 5. The ubiquity of std::vector The most useful container in the C++ standard library is std::vector
  • 6. Why std::vector is so useful std::vector is built from low-level memory management facili5es, such as pointers and arrays
  • 7. Why std::vector is so useful std::vector's primary role is to help us avoid the complexi4es of those facili4es
  • 8. Why std::vector is so useful That is, std::vector is designed to insulate us from some of the unpleasant aspects of real memory
  • 9. Building std::vector In the remainder, we will write a simplified std::vector implementa0on
  • 10. Building std::vector Namely, we will write a non-resizable version of std::vector for the limited case of int elements
  • 11. The vector_int class We will refer to this type as vector_int
  • 12. Why bother re-inven.ng the wheel when we already have std::vector?
  • 13. But why? The reason is that re-implemen0ng std::vector allows us to prac0ce many basic language facili0es at once β€’ Pointers & arrays β€’ Classes & operator overloading
  • 14. But why? Secondly, it allows stressing that whenever we design a class, we must consider ini#aliza#on, copying and destruc#on1 1 For simplicity, in the remainder we are going to deliberately ignore move seman8cs, i.e., we are going to discuss object lifecycle as of C++03
  • 15. But why? Finally, as computer scien2sts we need to know how to design and implement abstrac2ons such as std::vector
  • 16. Objec&ves Ideally, we would like to achieve the following: void f() { vector_int v(7); // varying number of elements v[0] = 7; // writing elements std::cout << v.size(); // it knows its size std::cout << v[1]; // values are default initialized vector_int w = v; // copy construction vector_int u; u = v; // assignment // automatic memory management // (no delete[] required) }
  • 17. Natural behavior vector_int provides us opera,ons that seem natural from the viewpoint of a user, rather than from the viewpoint of hardware
  • 18. Natural behavior We want to get to the point where we can program using types that provide exactly the proper4es we want based on logical needs
  • 19. Natural behavior To get there, we have to overcome a number of fundamental constraints related to access to the bare machine, such as: β€’ An object in memory is of fixed size β€’ An object in memory is in one specific place
  • 21. Designing vector_int We start our incremental design of vector_int by considering a very simple use: vector_int grades(4); grades[0] = 28; grades[1] = 27; grades[2] = 30: grades[3] = 25;
  • 22. Designing vector_int This creates a vector_int with four elements and give those elements the values 28, 27, 30, 25 vector_int grades(4); grades[0] = 28; grades[1] = 27; grades[2] = 30: grades[3] = 25;
  • 23. The size of a vector_int The number of elements of a vector_int is called its size vector_int grades(4); grades[0] = 28; grades[1] = 27; grades[2] = 30: grades[3] = 25;
  • 24. The size of a vector_int Therefore, the size of grades is four vector_int grades(4); grades[0] = 28; grades[1] = 27; grades[2] = 30: grades[3] = 25;
  • 25. The size of a vector_int Moreover, the number of elements of a vector_int are indexed from 0 to size - 1 vector_int grades(4); grades[0] = 28; grades[1] = 27; grades[2] = 30: grades[3] = 25;
  • 26. Represen'ng grades Graphically, we can represent grades like: grades[0] grades[1] grades[2] grades[3] β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” grades: β”‚ 4 β”‚ β”‚ β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
  • 27. How do we implement that drawing in code?
  • 28. vector_int is a class Unsurprisingly, we have to define a class and call it vector_int class vector_int { ... };
  • 29. Data members Obviously, we cannot design vector_int to have a fixed number of elements class vector_int { public: ... private: int elem0, elem1, elem2, elem3; };
  • 30. Data members Conversely, we need a data member that points to the sequence of elements class vector_int { public: ... private: int* elem; };
  • 31. Data members That is, we need a pointer member to the sequence of elements class vector_int { public: ... private: int* elem; };
  • 32. Data members Furthermore, we need a data member to hold the size of the sequence class vector_int { public: ... private: std::size_t sz; int* elem; };
  • 33. grades representa)on Therefore, a refined grades representa0on is as follows: elem[0] elem[1] elem[2] elem[3] β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ int[4] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” grades: β”‚ 4 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
  • 35. Ini$aliza$on At construc*on *me, we would like to allocate sufficient space for the elements on the heap // v allocates 4 ints on the heap vector_int v(4);
  • 36. Ini$aliza$on Elements will be later accessed through the data member v.elem class vector_int { public: ... private: std::size_t sz; int* elem; };
  • 37. Alloca&ng space To this end, we use new in the constructor to allocate space for the elements, and we let elem point to the address returned by new class vector_int { public: vector_int(std::size_t sz): elem(...) {} ... }
  • 38. Alloca&ng space To this end, we use new in the constructor to allocate space for the elements, and we let elem point to the address returned by new class vector_int { public: vector_int(std::size_t sz): elem(new int[sz]) {} ... }
  • 39. Storing the size Moreover, since there is no way to recover the size of the dynamic array from elem, we store it in sz class vector_int { public: vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {} ... };
  • 40. Storing the size We want users of vector_int to be able to get the number of elements
  • 41. size() access func)on Hence, we provide an access func2on size() that returns the number of elements class vector_int { public: vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {} std::size_t size() const { return sz; } private: std::size_t sz; int* elem; };
  • 42. Sensible ini)aliza)on In addi'on, we would like to ini'alize the newly-allocated elements to a sensible value vector_int v(3); std::cout << v[0]; // output: 0 (as opposed to some random values)
  • 43. Sensible ini)aliza)on Again, we can do that at construc2on 2me vector_int v(3); std::cout << v[0]; // output: 0 (as opposed to some random values)
  • 44. Sensible ini)aliza)on class vector_int { public: vector_int(std::size_t sz): sz(sz), elem(new int[sz]) { for (std::size_t i = 0; i < sz; ++i) elem[i] = 0; } std::size_t size() const { return sz; } private: std::size_t sz; int* elem; };
  • 45. Default constructor Moreover, in the case of containers, we have a natural default valid state, i.e., the empty container
  • 46. Default constructor Hence, we can introduce a default constructor class vector_int { public: vector_int(): sz(0), elem(nullptr) {} vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...} private: std::size_t sz; int* elem; };
  • 48. vector_int as a pointer Note that – up to this point – vector_int values are just pointers that remember the size of the pointed array vector_int v(4); std::cout << v.size(); // output: 4
  • 49. Accessing elements However, for a vector_int to be usable, we need a way to read and write elements vector_int v(4); v[0] = 1; // writing elements std::cout << v[0]; // reading elements
  • 50. Accessing elements That is, we would like to add the possibility of access elements through our usual subscript nota-on vector_int v(4); v[0] = 1; // writing elements std::cout << v[0]; // reading elements
  • 51. Operator func-on The way to get that is to define a member operator func,on operator[] vector_int v(4); v[0] = 1; // writing elements std::cout << v[0]; // reading elements
  • 52. Defining operator[] How can we define the operator[] overload? class vector_int { public: ... ??? operator[](std::size_t i) { ??? } private: std::size_t sz; int* elem; };
  • 53. Defining operator[] Intui&vely, one would say class vector_int { public: ... int operator[](std::size_t i) { return elem[i]; } private: std::size_t sz; int* elem; };
  • 54. Defining operator[] Apparently, we can now manipulate elements in a vector_int vector_int v(10); int x = v[2]; std::cout << x; // output: 0
  • 55. Naive implementa,on This looks good and simple, but unfortunately it is too simple int operator[](std::size_t i) { return elem[i]; }
  • 56. Naive implementa,on What happens when we write the following? vector_int v(10); v[3] = 7;
  • 57. Naive implementa,on We get a compile-)me error :-( vector_int v(10); v[3] = 7; // compile-time error!
  • 58. Returning a value Our implementa-on of operator[] returns a temporary of type int. Hence, we cannot assign any addi-onal value to it vector_int v(10); v[3] = 7;
  • 59. Returning a value That is, le+ng the subscript operator return a value enables reading but not wri6ng elements int operator[](std::size_t i) { return elem[i]; }
  • 60. Returning a reference Returning a reference, rather than a value, from the subscript operator solves this problem int& operator[](std::size_t i) { return elem[i]; }
  • 61. Returning a reference class vector_int { public: ... int& operator[](std::size_t i) { return elem[i]; } private: std::size_t sz; int* elem; };
  • 62. Constant vector_ints Our subscript operator has s/ll a problem, namely, it cannot be invoked for constant vector_ints void p(vector_int const& v) { int x = v[0]; }
  • 63. Constant vector_ints This is because operator[] has not been marked as const void p(vector_int const& v) { int x = v[0]; }
  • 64. Constant vector_ints However, we cannot simply mark operator[] as const, as it will prevent any further modifica9on to its elements void p(vector_int const& v) { int x = v[0]; }
  • 65. Const-overload To solve this, we provide an addi$onal overload of operator[] specifically meant for accessing const vectors class vector_int { public: ... int& operator[](std::size_t i) { return elem[i]; } int operator[](std::size_t i) const { return elem[i]; } private: std::size_t sz; int* elem; };
  • 66. Const-overload We can now access elements of constant vector_ints without preven4ng the possibility of modifying non-const vector_ints class vector_int { public: ... int& operator[](std::size_t i) { return elem[i]; } int operator[](std::size_t i) const { return elem[i]; } private: std::size_t sz; int* elem; };
  • 68. Resource acquisi,on No#ce that in the constructor we allocate memory for the elements using new class vector_int { public: vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {} ... };
  • 69. Memory leak However, when leaving f(), the heap-allocated elements pointed to by v.elem are not released void f() { vector_int v(10); int e = v[0]; };
  • 70. Memory leak We are therefore causing a memory leak void f() { vector_int v(10); int e = v[0]; };
  • 71. Fixing the leak To solve this, we must make sure that this memory is freed using delete[] void f() { vector_int v(10); int e = v[0]; // we should call delete[] before // returning from f() };
  • 72. The clean_up() member We could define a clean_up() member func0on class vector_int { public: vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...} void clean_up() { delete[] elem; } ... private: std::size_t sz; int* elem; };
  • 73. The clean_up() member We can then call clean_up() as follows void f() { vector_int v(10); int e = v[0]; v.clean_up(); };
  • 74. Releasing the memory Although that would work, one of the most common problems with the heap is that it is extremely easy to forget to call delete void f() { vector_int v(10); int e = v[0]; v.clean_up(); };
  • 75. Releasing the memory The equivalent problem would arise for clean_up() void f() { vector_int v(10); int e = v[0]; v.clean_up(); };
  • 76. Destructors Fortunately, C++ provides facili6es that allow us to do be:er than that
  • 77. Destructors In par'cular, in C++ each class is provided with a special func,on that makes sure that an object is properly cleaned up before it is destroyed
  • 78. Destructors Such a special func.on is called the destructor
  • 79. Destructors The destructor is a public member func-ons with no input parameters and no return type class vector_int { public: ~vector_int() {...} ... };
  • 80. Destructors The destructor has the same name as the class, but with a !lde (~) in front of it class vector_int { public: ~vector_int() {...} ... };
  • 81. Implemen'ng ~vector_int() class vector_int { public: vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...} ~vector_int() { ??? } ... private: std::size_t sz; int* elem; };
  • 82. Implemen'ng ~vector_int() class vector_int { public: vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...} ~vector_int() { delete[] elem; } ... private: std::size_t sz; int* elem; };
  • 83. Automa'c memory dealloca'on Thanks to the presence of the destructor, we do not need to explicitly release memory void f() { vector_int v(10); int e = v[0]; // Hurray! the dynamic arrays pointed to // by v.elem is automatically deleted };
  • 84. Automa'c memory dealloca'on The tremendous advantage is that a vector cannot forget to call its destructor to deallocate the memory used for its elements
  • 85. Synthesized destructors If we do not explicitly provide a destructor, the compiler will generate a synthesized destructor
  • 86. Synthesized destructors Such a synthesized destructor invokes the destructors for the elements (if they have destructors)
  • 87. vector_int synth. destructor Since sz and elem do not provide a destructor, the synthesized destructor would simply reduce to an empty func8on class vector_int { public: // synthesized destructor ~vector_int() {} ... private: std::size_t sz; int* elem; };
  • 88. vector_int synth. destructor This is why we end up with a memory leak if we do not explicitly specify a destructor for vector_int class vector_int { public: // synthesized destructor ~vector_int() {} ... private: std::size_t sz; int* elem; };
  • 90. Copying two vector_ints Let us try to copy one vector_int into another void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; // what happens? }
  • 91. Copying two vector_ints Ideally we would like w to become a copy of v void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; // what happens? }
  • 92. Copy seman+cs That means: β€’ w.size() == v.size() β€’ w[i] == v[i] for all i's in [0:v.size()) β€’ &w[i] != &v[i] for all i's in [0:v.size())
  • 93. Copy seman+cs β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” v: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” w: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ β”‚ └──────────┐ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • 94. Copy seman+cs Furthermore, we want all memory to be released once returning from h() void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; // here, v.elem and w.elem get released }
  • 95. Wrong copy behavior Unfortunately, this is not what happens with our vector_int implementa4on
  • 96. Copying is ini*alizing First, note that w is ini#alized from v void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; }
  • 97. Copying is ini*alizing We know that ini#aliza#on is done by a constructor void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; }
  • 98. Copying is ini*alizing Hence, we have to conclude that vector_int provides a constructor that accepts vector_ints as its only input argument vector_int(vector_int const& v) {...}
  • 99. Copying is ini*alizing This is made even more evident if we use an equivalent nota4on for the last line in h() void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w(v); // the same as: vector_int w = v; }
  • 100. Copying is ini*alizing However, we never wrote such a constructor
  • 101. Copy constructor It turns out that every class in C++ is provided with a special constructor called copy constructor vector_int(vector_int const& v) {...}
  • 102. Copy constructor A copy constructor is defined to take as its argument a constant reference to the object from which to copy vector_int(vector_int const& v) {...}
  • 103. vector_int's constructors class vector_int { public: vector_int(): sz(0), elem(nullptr) {} vector_int(std::size_t sz): sz(sz), elem(new int[sz]) {...} vector_int(vector_int const& v) { ... } private: std::size_t sz; int* elem; };
  • 104. Const-reference Note that the v is passed by reference vector_int(vector_int const& v) {...}
  • 105. Const-reference Why don't we pass v by value? vector_int(vector_int const& v) {...}
  • 106. Const-reference Passing by value would require v to be copied... vector_int(vector_int const& v) {...}
  • 107. Const-reference ...which would in turn cause the invoca2on of v's copy constructor... vector_int(vector_int const& v) {...}
  • 108. Const-reference ...thus leading to an infinite loop! vector_int(vector_int const& v) {...}
  • 109. Synthesized copy constructor If we do not provide an explicit copy constructor, the compiler will generate a synthesized one for us
  • 110. Synthesized copy constructor Synthesized copy constructors simply perform memberwise copy class vector_int { public: // synthesized copy constructor vector_int(vector_int const& v): sz(v.sz), elem(v.elem) {} ... private: std::size_t sz; int* elem; };
  • 111. Copying pointers However, memberwise copying in the presence of pointer members (such as elem) usually causes problems // synthesized copy constructor vector_int(vector_int const& v): sz(v.sz), elem(v.elem) {}
  • 112. Copying pointers Specifically, w ends up sharing v's elements void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; }
  • 113. Sharing elements sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” w: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ β”‚ └──────────┐ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” v: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
  • 114. Sharing elements What is the output? vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; w[0] = 10; std::cout << v[0];
  • 115. Sharing elements What is the output? vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; w[0] = 10; std::cout << v[0]; // output: 10
  • 116. Double dele)on Moreover, when we return from h() the destructors for v and w are implicitly called void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; }
  • 117. Double dele)on Due to their hidden connec-on, both v and w will try to release the same memory area
  • 118. A working copy constructor Hence, we need to explicitly provide a copy constructor that will 1. set the number of elements (i.e., the size) 2. allocate memory for its elements 3. copying the elements from the source vector_int
  • 119. A working copy constructor class vector_int { public: vector_int(vector_int const& v): sz(v.sz), elem(new int[v.sz]) { std::copy(v.elem, v.elem + sz, elem); } ... private: std::size_t sz; int* elem; };
  • 120. A working copy constructor void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; }
  • 121. A working copy constructor β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” v: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” w: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ β”‚ └──────────┐ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • 122. No more double dele+on Given that the two vector_ints are now independent, the two destructors can do the right thing void h() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w = v; }
  • 124. Assignment Even though we now correctly handle copy construc4on, vector_ints can s4ll be copied by assignment void g() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w(4); w = v; }
  • 125. Assignment What happens when we execute the following? void g() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w(4); w = v; // what happens? }
  • 126. Memory leak and double dele/on Unfortunately, we once again end up with a memory leak and a double dele-on void g() { vector_int v(3); v[0] = 7; v[1] = 3; v[2] = 8; vector_int w(4); w = v; }
  • 127. Synthesized assignment operator As a ma&er of fact, if we do not provide any overload for the assignment operator, the compiler will synthesize one for us
  • 128. Synthesized assignment operator Synth. assignment operators perform memberwise assignment class vector_int { public: // synthesized assignment operator vector_int& operator=(vector_int const& v) { sz = v.sz; elem = v.elem; return *this; } ... private: std::size_t sz; int* elem; };
  • 129. Synthesized assignment operator β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 0 β”‚ 0 β”‚ 0 β”‚ 0 β”‚ int[4] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” w: β”‚ 4 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” v: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
  • 130. Synthesized assignment operator β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 0 β”‚ 0 β”‚ 0 β”‚ 0 β”‚ int[4] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” w: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ β”‚ └──────────┐ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 7 β”‚ 3 β”‚ 8 β”‚ int[3] β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–² β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ sz elem β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” v: β”‚ 3 β”‚ β”‚ vector_int β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
  • 131. Synth. assignment for vector_int Since we did not provide an explicit overload for operator=, the synthesized assignment is used vector_int& operator=(vector_int const& v) {...}
  • 132. Working assignment operator The remedy for the assignment is fundamentally the same as for the copy constructor vector_int& operator=(vector_int const& v) {...}
  • 133. Working assignment operator class vector_int { public: vector_int& operator=(vector_int const& v) { int* p = new int[v.sz]; std::copy(v.elem, v.elem + v.sz, p); delete[] elem; elem = p; sz = v.sz; return *this; } ... private: std::size_t sz; int* elem; };
  • 135. Destructors are fundamental Destructors are conceptually simple but are the founda'on for many of the most effec5ve C++ programming techniques
  • 136. Destructors are fundamental The usage of the constructor / destructor pair for correctly managing heap-allocated memory is the archetypical example
  • 137. Resource wrappers need destructors More generally, a class needs a destructor if it acquires resources
  • 138. Resource A resource is something we get from somewhere and that we must give back once we have finished using it β€’ Memory β€’ File descriptor β€’ Socket β€’ ...
  • 139. The big three A class that needs a destructor almost always needs a copy construc-on and assignment
  • 140. The big three The reason is that if an object has acquired a resource the default meaning of copy is almost certainly wrong
  • 141. The rule of three This is summarised in the so-called rule of three2 If you need to explicitly declare either the destructor, copy constructor or assignment operator yourself, you probably need to explicitly declare all three of them 2 Once again, we are limi/ng ourselves to C++03, in C++11 one would obey either the rule of five or the rule of zero
  • 143. Bibliography β€’ B. Stroustrup, The C++ Programming Language (4th ed.) β€’ B, Stroustrup, Programming: Principles and Prac@ce Using C++ (2nd ed.) β€’ A. Stepanov, Notes on programming β€’ StackOverflow FAQ, What is the rule of three?