SlideShare una empresa de Scribd logo
1 de 143
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?

Más contenido relacionado

La actualidad más candente

La actualidad más candente (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++
 

Destacado

Ays Summer Meet the Stars
Ays Summer Meet the StarsAys Summer Meet the Stars
Ays Summer Meet the StarsAysSummer
 
Partnering with communities in Colorado
Partnering with communities in ColoradoPartnering with communities in Colorado
Partnering with communities in ColoradoDonald Nease
 
Business health check business infoload 2016
Business health check   business infoload 2016Business health check   business infoload 2016
Business health check business infoload 2016Infoload
 
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 IndustryPriyadarshani 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 loopmohamed sikander
 
C++ Standard Template Library
C++ Standard Template LibraryC++ Standard Template Library
C++ Standard Template LibraryIlio Catallo
 

Destacado (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 a Resource wrappers in C++

Oops lab manual2
Oops lab manual2Oops lab manual2
Oops lab manual2Mouna Guru
 
Vector class in C++
Vector class in C++Vector class in C++
Vector class in C++Jawad Khan
 
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 & ArraysBlue 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.docxPhil4IDBrownh
 
CLASSES, STRUCTURE,UNION in C++
CLASSES, STRUCTURE,UNION in C++CLASSES, STRUCTURE,UNION in C++
CLASSES, STRUCTURE,UNION in C++Prof Ansari
 
Arrays, Structures And Enums
Arrays, Structures And EnumsArrays, Structures And Enums
Arrays, Structures And EnumsBhushan Mulmule
 
OOP program questions with answers
OOP program questions with answersOOP program questions with answers
OOP program questions with answersQuratulain 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.pdffashionfootwear1
 
Generics in .NET, C++ and Java
Generics in .NET, C++ and JavaGenerics in .NET, C++ and Java
Generics in .NET, C++ and JavaSasha Goldshtein
 

Similar a Resource wrappers in C++ (20)

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
 
Generics in .NET, C++ and Java
Generics in .NET, C++ and JavaGenerics in .NET, C++ and Java
Generics in .NET, C++ and Java
 

Más de 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 layersIlio Catallo
 
Java and Java platforms
Java and Java platformsJava and Java platforms
Java and Java platformsIlio Catallo
 
Spring MVC - Web Forms
Spring MVC  - Web FormsSpring MVC  - Web Forms
Spring MVC - Web FormsIlio Catallo
 
Spring MVC - The Basics
Spring MVC -  The BasicsSpring MVC -  The Basics
Spring MVC - The BasicsIlio Catallo
 
Web application architecture
Web application architectureWeb application architecture
Web application architectureIlio Catallo
 
Introduction To Spring
Introduction To SpringIntroduction To Spring
Introduction To SpringIlio Catallo
 
Gestione della memoria in C++
Gestione della memoria in C++Gestione della memoria in C++
Gestione della memoria in C++Ilio Catallo
 
Puntatori e Riferimenti
Puntatori e RiferimentiPuntatori e Riferimenti
Puntatori e RiferimentiIlio Catallo
 
Java Persistence API
Java Persistence APIJava Persistence API
Java Persistence APIIlio Catallo
 
JSP Standard Tag Library
JSP Standard Tag LibraryJSP Standard Tag Library
JSP Standard Tag LibraryIlio Catallo
 
Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3Ilio Catallo
 
Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3Ilio Catallo
 
Introduction to Struts 1.3
Introduction to Struts 1.3Introduction to Struts 1.3
Introduction to Struts 1.3Ilio 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
 

Más de 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
 

Último

Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 

Último (20)

Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 

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?