RAII
mutable
class C {
int member;
void foo() const {
member = 42;
}
};mutable
class C {
mutable int member;
void foo() const {
member = 42;
}
};Constructors
class Stack {
private:
std::vector<int> data;
public:
static Stack createEmpty() {
Stack s;
return s;
}
static Stack createFromVector(const std::vector<int>& numbers) {
Stack s;
s.data = numbers;
return s;
}
static Stack createFromExisting(const Stack& st) {
return createFromVector(st.data);
}
...
};Stack s1 = Stack::createFromEmpty();
Stack s2 = Stack::createFromVector(v);
Stack s3 = Stack::createFromExisting(s2);Constructors
class Stack {
private:
std::vector<int> data;
public:
static Stack create() {
Stack s;
return s;
}
static Stack create(const std::vector<int>& numbers) {
Stack s;
s.data = numbers;
return s;
}
static Stack create(const Stack& st) {
return createFromVector(st.data);
}
...
};Stack s1 = Stack::create();
Stack s2 = Stack::create(v);
Stack s3 = Stack::create(s2);Constructors
class Stack {
private:
std::vector<int> data;
public:
Stack()
{
}
Stack(const std::vector<int>& numbers) {
data = numbers;
}
Stack(const Stack& st) {
data = st.data;
}
...
};Stack s1 = Stack();
Stack s2 = Stack(v);
Stack s3 = Stack(s2);Constructors
class Stack {
private:
std::vector<int> data;
public:
Stack()
{
}
Stack(const std::vector<int>& numbers) {
data = numbers;
}
Stack(const Stack& st) {
data = st.data;
}
...
};Stack s1;
Stack s2{v};
Stack s3{s2};Constructors
class Stack {
private:
std::vector<int> data;
public:
Stack()
{
}
Stack(const std::vector<int>& numbers) {
data = numbers;
}
Stack(const Stack& st) {
data = st.data;
}
...
};const Stack s1;
const Stack s2{v}; // error
const Stack s3{s2}; // errorConstructors
class Stack {
private:
std::vector<int> data;
public:
Stack()
{
}
Stack(const std::vector<int>& numbers) :
data{numbers}
{
}
Stack(const Stack& st) :
data{st.data}
{
}
...
};const Stack s1;
const Stack s2{v};
const Stack s3{s2};Constructors
class ClassName {
T1 member1;
T2 member2;
T3 member3;
...
TN memberN;
ClassName(args) :
member1{...},
member2{...},
member3{...},
...
memberN{...}
{
...
}
};auto c1 = ClassName{args};
auto c2 = ClassName(args);
ClassName c3 = {args};
ClassName c4{args};
ClassName c5(args);new ClassName(args);
new ClassName{args};Constructor
class ClassName {
T1 member1;
T2 member2;
T3 member3;
...
TN memberN;
ClassName() :
member1{...},
member2{...},
member3{...},
...
memberN{...}
{
...
}
};ClassName c1;
auto c2 = ClassName{};
auto c3 = ClassName();
ClassName c4 = {};
ClassName c5{};
ClassName c6();new ClassName;
new ClassName();
new ClassName{};Default
class C {
T1 member1;
T1 member2;
C(args) :
member2{...}
// member1
// default-constructed
{
}
}Constructor
Default
struct Cls {
std::vector<int> v;
int coeff;
};struct Cls {
std::vector<int> v;
int coeff;
Cls()
{
}
};struct Cls {
std::vector<int> v;
int coeff;
Cls() :
v{}
{
}
};Implicitly defined
Constructor
Default
struct Cls {
std::vector<int> v;
int coeff;
Cls(args) {...}
};struct Cls {
std::vector<int> v;
int coeff;
Cls(args) {...}
Cls()
{
}
};struct Cls {
std::vector<int> v;
int coeff;
Cls(args) {...}
Cls() :
v{}
{
}
};Implicitly defined
Constructor
Default
struct Cls {
std::vector<int> v;
int coeff;
Cls(args) {...}
Cls() = default;
};struct Cls {
std::vector<int> v;
int coeff;
Cls(args) {...}
Cls()
{
}
};struct Cls {
std::vector<int> v;
int coeff;
Cls(args) {...}
Cls() :
v{}
{
}
};Explicitly defaulted
Constructor
Default
Explicitly deleted
struct Cls {
std::vector<int> v;
int coeff;
};struct Cls {
std::vector<int> v;
int coeff;
Cls()
{
}
};struct Cls {
std::vector<int> v;
int coeff;
Cls() :
v{}
{
}
};Constructor
Default
Explicitly deleted
struct Cls {
std::vector<int> v;
int coeff;
Cls() = delete;
};struct Cls {
std::vector<int> v;
int coeff;
Cls()
{
}
};struct Cls {
std::vector<int> v;
int coeff;
Cls() :
v{}
{
}
};Constructor
Default
Trivial
struct Cls {
std::vector<int> v;
int coeff;
Cls() = default;
};struct point2D {
int x, y;
point2D() = default;
};non trivial
trivial
Constructor
Default
struct Cls {
std::vector<int> v;
int coeff;
Cls() = default;
};struct point2D {
int x, y;
point2D() = default;
};no-throw default constructible
trivially default constructible
struct Cls {
std::vector<int> v;
int coeff;
Cls() noexcept
= default;
};default constructible
#include <type_traits>
#include <type_traits>
#include <type_traits>
std::is_trivially_default_constructible_v<Cls>
std::is_nothrow_default_constructible_v<Cls>
std::is_default_constructible_v<Cls>
Constructor
struct Cls {
std::vector<int> x;
int y;
// implicitly defined
};
Cls p1;
// p1.x == {}
// p1.y undefined
Cls p2{};
// p1.x == {}
// p1.y == 0Default
struct Cls {
std::vector<int> x;
int y;
Cls()
{
}
};
Cls p1;
// p1.x == {}
// p1.y undefined
Cls p2{};
// p1.x == {}
// p1.y undefinedstruct Cls {
std::vector<int> x;
int y;
Cls() : x{}, y{}
{
}
};
Cls p1;
// p1.x == {}
// p1.y == 0
Cls p2{};
// p1.x == {}
// p1.y == 0Defaulted
default constructor
User defined default constructor
User defined default constructor
struct Cls {
std::vector<int> x;
int y;
Cls() = default;
};
Cls p1;
// p1.x == {}
// p1.y undefined
Cls p2{};
// p1.x == {}
// p1.y == 0point2D p1;
point2D p2{};
default initialization
value initialization
RAII and lifetime
- Storage allocation or reuse
- Object construction
- Â ... Object is alive ...
- Object destruction
- Storage deallocation or reuse
{
std::string s;
// storage allocated on stack
// std::string constructor invoked
// internal string buffer allocated
// size set to 0
}
// storage deallocated on stack
// std::string destructor invoked
// internal string buffer deallocatedRAII
Resource Acquisition Is Initialization
new
delete
fopen
fclose
libcreate
libdestroy
lock
unlock
RAII
Resource Acquisition Is Initialization
setup1();
setup2();
setup3();
...
work();
...
teardown3();
teardown2();
// forgot to teardown1()!setup();
...
work(); // exception thrown
...
teardown(); // not reachedsetup();
bool cleaned = false;
...
try {
work();
catch(...) {
cleaned = true;
teardown();
}
...
if (!cleaned) {
teardown();
}setup1();
setup2();
setup3();
...
work();
...
teardown3();
teardown2();
teardown1();setup1();
setup2();
setup3();
...
work();
...
// wrong order
teardown1();
teardown2();
teardown3();setup1();
setup2();
setup3();
...
work();
...
teardown3();
teardown2();
teardown1();RAII
Resource Acquisition Is Initialization
new
delete
fopen
fclose
libcreate
libdestroy
lock
unlock
Constructor
Destructor
destructors
class Resource {
Resource(args) {
// construct
}
~Resource() {
// destruct
}
};{
// Resource::Resource()
Resource r;
work(r);
} // Resource::~Resource()ClassName(args)
~ClassName()
Constructor
Destructor
class SmartArray {
private:
int* _data;
size_t _size;
public:
SmartArray(size_t size) :
_data{new int[size]},
_size{size}
{
}
~SmartArray() {
delete[] _data;
}
int& at(int i) {
return _data[i];
}
const int& at(int i) const {
return _data[i];
}
size_t size() {
return _size;
}
};{
SmartArray ar{10};
for (int i = 0; i < ar.size(); ++i) {
ar.at(i) = i * i;
}
} // SmartArray::~SmartArray()destructors
Constructors
class C {
public:
C();
C(int arg1 = 42);
};Default constructor
Copy constructor
Move constructor
Explicit constructor
class C {
public:
C(const C&);
};class C {
public:
C(C&&);
};class C {
public:
explicit C(char);
};C c1;
// C c1(); most vexing parse
C c2{};
new C;
...C c3 = c1;
C c4{c1};
f(c1); // if by value
...C c4 = createTemporary();
C c5 = std::move(c2);C c1 = 'c'; // error
f('c'); // error (f takes C)
return 'c'; // error (returns C)
...Constructor
explicit
class SmartArray {
private:
int* _data;
size_t _size;
public:
SmartArray(size_t size) :
_data{new int[size]},
_size{size}
{
}
~SmartArray() {
delete[] _data;
}
int& at(int i) {
return _data[i];
}
const int& at(int i) const {
return _data[i];
}
size_t size() {
return _size;
}
};Explicit constructor
SmartArray f(const SmartArray& ar) {
return 10;
}
void g() {
SmartArray ar1 = static_cast<SmartArray>(10);
SmartArray ar2 = 10;
SmartArray ar3 = {10};
f(10);
}converting constructor
Constructor
explicit
class SmartArray {
private:
int* _data;
size_t _size;
public:
explicit SmartArray(size_t size) :
_data{new int[size]},
_size{size}
{
}
~SmartArray() {
delete[] _data;
}
int& at(int i) {
return _data[i];
}
const int& at(int i) const {
return _data[i];
}
size_t size() {
return _size;
}
};Explicit constructor
SmartArray f(const SmartArray& ar) {
return 10;
}
void g() {
SmartArray ar1 = static_cast<SmartArray>(10);
SmartArray ar2 = 10;
SmartArray ar3 = {10};
f(10);
}explicit constructor
SmartArray ar = {2, 3, 4, 5, 7};std::initializer_list
class SmartArray {
private:
int* _data;
size_t _size;
public:
explicit SmartArray(size_t size) :
_data{new int[size]},
_size{size}
{
}
~SmartArray() {
delete[] _data;
}
int& at(int i) {
return _data[i];
}
const int& at(int i) const {
return _data[i];
}
size_t size() {
return _size;
}
};class SmartArray {
private:
int* _data;
size_t _size;
public:
explicit SmartArray(size_t size) :
_data{new int[size]},
_size{size}
{
}
SmartArray(std::initializer_list<int> il) :
_data{new int[il.size()]},
_size{il.size()}
{
std::copy_n(il.begin(), il.size(), _data);
}
~SmartArray() {
delete[] _data;
}
int& at(int i) {
return _data[i];
}
const int& at(int i) const {
return _data[i];
}
size_t size() {
return _size;
}
};SmartArray ar = {2, 3, 4, 5, 7};std::initializer_list
struct point2D {
int x, y;
point2D() :
x{13},
y{42}
{
}
}in-class initializers
struct point2D {
int x = 13, y = 42;
}=
struct point2D {
int x, y = 42;
point2D() :
x{13}
{
// y == 42
}
}in-class initializers
T obj;
T object {};
T()
T{}
new T()
new T{}
Class::Class(...) : member() { ... }
Class::Class(...) : member{} { ... }T object(args...);
T object{arg};
T(args);
static_cast<T>(obj)
new T(args...)
Class::Class() : member(args...) { ... }
[arg](){ ... }T object = other;
T object = {other};
f(other)
return other;
throw object;
catch (T object)
T array[N] = {other};T object{args...};
T{args...}
new T{args...}
class { T member{args...}; }
Class::Class() : member{args...} { ... }T object = {args...};
f({args...})
return {args...} ;
object[{args...}]
object = {args...}
U({args...})
Class { T member = {args...}; };T object = {args...};
T object{args...};
T object = { .designator = arg1 , .designator { arg2 } ... };
T object { .designator = arg1 , .designator { arg2 } ... };
T object(args...);T& ref = object;
T& ref = {args...};
T& ref(object);
T& ref{args...};
T&& ref = object;
T&& ref = {args...};
T&& ref(object) ;
T&& ref{args...};
f(object)
f({args...})
return object;
Class::Class(...) : ref(object) {...}Default
Value
Direct
Copy
Direct list
Copy list
Aggregate
Reference
initialization
To be continued...
RAII
RAII
inheritance
virtual
- constructor
- member initializer list
- destructor
- default constructor
- std::initializer_list
- in-class initializer
- copy ctor
- cpy assign op
- move ctor
- mv assign op
- default members
- deleted members
- rule of 0
- rule of 3/5
- smart-ptrs
- converting constructor
- explicit specifier
- is-a relation
- has-a relation
- public inheritance
- final specifier
- using declaration
- empty base optimization
- protected members
- private & protected inheritance
- multiple inheritance
- diamond problem
- base method hiding problem
- virtual methods
- override specifier
- dynamic type
- RTTI
- dynamic_cast
- typeid
- vtables
- by value passing problem
- pure virtual function
- abstract class
misc
- friends
- nested members
- conversion operators
- operator overloading
- member pointers
- unions
- std optional
- std variant
- std any
- user defined literal
RAII
By Jan Bielak
RAII
A presentation about constructors, destructors and RAII. It is presented here: https://www.youtube.com/watch?v=yDrIHAS2JgY .
- 831