smart pointers
and inheritance
references and ownership
Returning values
Type func(); Type& func(); const Type& func(); Type* func(); const Type* func(); const Type func(); Type&& func(); const Type&& func();
Taking parameters
Readble | Writable | Transfers ownership |
---|---|---|
Yes | Yes | Yes |
Yes | Yes | No |
Yes | No | No |
Yes | Yes | Depends |
Yes | No | Depends |
Yes | No | Yes |
Yes | Yes | Yes |
Yes | No | Yes |
void func(Type); void func(Type&); void func(const Type&); void func(Type&&); void func(Type*); void func(const Type*); void func(const Type); void func(const Type&&);
Reads | Modifies | Takes ownership |
---|---|---|
Yes | No | No |
Depends | Yes | No |
Yes | No | No |
Yes | Yes | Yes |
Depends | Depends | Depends |
Yes | No | Depends |
Yes | No | No |
Yes | No | Yes |
smart pointers
std::unique_ptr
std::shared_ptr std::weak_ptr
unique_ptr
shared_ptr
weak_ptr
shared_ptr
weak_ptr
resource
resource
std::unique_ptr
std::unique_ptr<T> std::unique_ptr<T>{new-allocated-pointer} std::unique_ptr<T, DeleterT>{pointer, deleter} std::make_unique<T>(initializer) std::make_unique<T[]>(array-size) std::make_unique_for_overwrite<T>() std::make_unique_for_overwrite<T[]>(array-size)
std::unique_ptr
auto createSequence(size_t length) {
auto seq = std::make_unique_for_overwrite<int[]>(length);
seq[0] = seq[1] = 1;
for (int i = 2; i < length; ++i) {
seq[i] = seq[i - 2] + seq[i - 1];
}
return seq;
};
auto fopenUnique(const char* filename, const char* flags) {
return std::unique_ptr<std::FILE, int(*)(std::FILE*)>{
std::fopen(filename, flags), &std::fclose};
}
int* ar = new int[10];
// adopt existing resource
auto unique_ar = std::unique_ptr<int[]>{ar};
// construct new resource
auto my_p = std::make_unique<int[]>(5);
// release ownership and aquire new resource
unique_ar = some_ptr;
// steal ownership
unique_ar = std::move(my_p);
std::shared_ptr
shared_ptr
resource
use_count:
1
Reference counting
std::shared_ptr
shared_ptr
resource
use_count:
1
weak_ptr
Reference counting
std::shared_ptr
shared_ptr
resource
use_count:
1
weak_ptr
weak_ptr
Reference counting
std::shared_ptr
shared_ptr
resource
use_count:
2
weak_ptr
weak_ptr
shared_ptr
Reference counting
std::shared_ptr
shared_ptr
resource
use_count:
2
weak_ptr
shared_ptr
Reference counting
std::shared_ptr
shared_ptr
resource
use_count:
1
weak_ptr
Reference counting
std::shared_ptr
weak_ptr
Reference counting
use_count:
0
std::shared_ptr
Reference counting
resource
use_count
shared_ptr
shared_ptr
shared_ptr
std::shared_ptr
Reference counting
resource
use_count
shared_ptr
shared_ptr
std::shared_ptr
Reference counting
resource
use_count
shared_ptr(new Object{args})
resource
use_count
make_shared<Object>(args)
std::shared_ptr
Reference counting
resource
use_count
Resource* ptr = new Resource{};
std::shared_ptr smart1{ptr};
std::shared_ptr smart2{smart1};
std::shared_ptr smart3{ptr};
std::shared_ptr smart4{smart1};
use_count
smart1
smart2
smart3
smart4
std::shared_ptr
std::shared_ptr<T> std::shared_ptr{new-allocated-pointer} std::shared_ptr<T, DeleterT>{pointer, deleter} std::shared_ptr<T>{shared-ptr} std::shared_ptr<T>{weak-ptr} std::shared_ptr<T>{unique-ptr} std::shared_ptr<T>{shared-ptr, pointer} std::make_shared<T>(initializer) std::make_shared<T[]>(array-size) std::make_shared_for_overwrite<T>() std::make_shared_for_overwrite<T[]>(array-size) weak_ptr.lock() std::enable_shared_from_this shared_ptr.use_count()
aliasing constructor
std::shared_ptr
std::unique_ptr<int[]> createSequence(size_t length);
// steal from unique_ptr
std::shared_ptr<int[]> shared = createSequence(10);
auto shared1 = std::make_shared<std::string>("Hello");
auto shared2 = shared1; // copy ownership
std::weak_ptr weak = shared1; // only access
// (1)
auto reader1 = weak.lock(); // read through weak_ptr
if (!reader1) // weak_ptr could've been expired
std::cout << "expired";
else
somePointerUser(*reader1);
// (2)
std::shared_ptr reader2{weak}; // throws if expired
somePointerUser(*reader2);
assert(shared1.use_count() == 4);
struct point { int x, y; };
auto point_ptr = std::make_shared<point>(3, 5);
auto coord_ptr = std::shared_ptr<int>(point_ptr, &point_ptr->x);
std::weak_ptr
resource
resource
resource
resource
resource
resource
std::weak_ptr
resource
resource
resource
resource
resource
resource
std::weak_ptr
resource
resource
resource
resource
resource
resource
pointers
- Storing values
- Unique ownership
- Automatic variables
- std::unique_ptr
- raw pointer/handle + RAII wrapper
- Shared ownership
-
std::shared_pointer
-
std::weak_ptr
-
- Unique ownership
- Taking parameters
- By value or reference
- By owning class (like smart pointer)
- By raw pointer
-
Returning values
- By value or reference
- By owning class (like smart pointer)
- By raw pointer
inheritance
Has-a and Is-a object RELATIONSHIP
Has-A
is-a
computer
- Motherboard
- Processor
- Memory
- Storage
- Graphics Card
computer
- Turing machine
- Electronic device
- Hardware
Has-A
is-a
Has-a RELATIONSHIP
Has-A
struct Person {
int age;
std::string name;
Job occupation;
};
person
- age
- name
- occupation
class Array {
private:
int* data; // raw pointer encapsulated
size_t capacity;
public:
int& operator[](size_t idx);
const int& operator[](size_t idx) const;
...
};
array
- array elements
- size
Is-a RELATIONSHIP
is-a
inheritance
base
derived
Is-a RELATIONSHIP
is-a
inheritance
base
derived
- base members
- base methods
- derived members
- derived methods
base
- base members
- base methods
Is-a RELATIONSHIP
is-a
inheritance
base
derived
- base members
- base methods
- derived members
- derived methods
base
- base members
- base methods
Is-a RELATIONSHIP
is-a
inheritance
shape
rectangle
- position
- draw()
- width
- height
Shape
- position
- draw()
inheritance
public
inheritance
private
inheritance
protected
inheritance
Has-A
Has-A
is-a
public inheritance
public
inheritance
is-a
Is-A RELATIONSHIP
class Base {
};
class Derived : public Base {
};
Derived
Base
is-a
public inheritance
public
inheritance
is-a
Is-A RELATIONSHIP
class Base {
int x, y;
};
class Derived : public Base {
int z, w;
};
memory location
object
derived
z
Base
w
Base
x
y
public inheritance
public
inheritance
is-a
Is-A RELATIONSHIP
class Base {
int x, y;
};
class Derived : public Base {
int z, w;
};
memory location
object
derived
z
Base
w
Base
x
y
Empty Base Optimisation if
sizeof(Base) == 0
public inheritance
public
inheritance
is-a
Is-A RELATIONSHIP
class Base {
int x, y;
};
class Derived : public Base {
int z, w;
};
Derived derived;
Base* pBase = &derived;
Base& refBase = derived;
public inheritance
public
inheritance
is-a
Is-A RELATIONSHIP
class Base {
public:
void methodOnBase() {
std::cout << "base\n";
}
};
class Derived : public Base {
public:
void methodOnDerived() {
std::cout << "derived\n";
}
};
Base base;
base.methodOnBase();
Derived derived;
derived.methodOnDerived();
derived.methodOnBase();
public inheritance
public
inheritance
is-a
Is-A RELATIONSHIP
class Base {
public:
int data;
void methodOnBase() {
std::cout << data;
}
};
class Derived : public Base {
public:
void methodOnDerived() {
std::cout << data + 143;
}
};
Base base;
base.methodOnBase();
base.data = 245;
Derived derived;
derived.methodOnDerived();
derived.methodOnBase();
derived.data = 1252;
protected access
class Base {
public:
int data;
void methodOnBase() {
std::cout << data;
}
};
class Derived : public Base {
public:
void methodOnDerived() {
std::cout << data + 143;
}
};
Base base;
base.methodOnBase();
base.data = 245;
Derived derived;
derived.methodOnDerived();
derived.methodOnBase();
derived.data = 1252;
class Base {
int data;
public:
void methodOnBase() {
std::cout << data;
}
};
class Derived : public Base {
public:
void methodOnDerived() {
std::cout << data + 143;
}
};
Base base;
base.methodOnBase();
base.data = 245;
Derived derived;
derived.methodOnDerived();
derived.methodOnBase();
derived.data = 1252;
protected access
class Base {
protected:
int data;
public:
void methodOnBase() {
std::cout << data;
}
};
class Derived : public Base {
public:
void methodOnDerived() {
std::cout << data + 143;
}
};
Base base;
base.methodOnBase();
base.data = 245;
Derived derived;
derived.methodOnDerived();
derived.methodOnBase();
derived.data = 1252;
protected access
class Base {
protected:
int data;
public:
void methodOnBase() {
std::cout << data;
}
};
class Derived : public Base {
public:
void methodOnDerived() {
std::cout << data + 143;
}
};
Base base;
base.methodOnBase();
base.data = 245;
Derived derived;
derived.methodOnDerived();
derived.methodOnBase();
derived.data = 1252;
using declaration
class Base {
protected:
int data;
public:
void methodOnBase() {
std::cout << data;
}
};
class Derived : public Base {
public:
using Base::data;
void methodOnDerived() {
std::cout << data + 143;
}
};
Base base;
base.methodOnBase();
base.data = 245;
Derived derived;
derived.methodOnDerived();
derived.methodOnBase();
derived.data = 1252;
using declaration
class Base {
public:
void f() {
std::cout << "base";
};
};
class Derived : public Base {
};
Base base;
base.f(); // base
Derived derived;
derived.f(); // base
shadowing
class Base {
public:
void f() {
std::cout << "base";
};
};
class Derived : public Base {
public:
void f() {
std::cout << "derived";
};
};
Base base;
base.f(); // base
Derived derived;
derived.f(); // derived
shadowing
class Base {
public:
void f() {
std::cout << "base";
};
};
class Derived : public Base {
public:
void f(int x) {
std::cout << x;
};
};
Base base;
base.f(); // base
Derived derived;
derived.f(); // ERROR
derived.f(15); // 15
shadowing
class Base {
public:
void f() {
std::cout << "base";
};
};
class Derived : public Base {
public:
using Base::f;
void f(int x) {
std::cout << x;
};
};
Base base;
base.f(); // base
Derived derived;
derived.f(); // ERROR
derived.f(15); // 15
shadowing
public inheritance
dog
terrier
shows relationship
code reuse
polymorphism
class Dog {
void bark();
};
class Terrier : public Dog {
void hunt();
};
class Dog {
virtual void bark();
};
class Terrier : public Dog {
void hunt() override;
};
type erasure, CRTP...
POLYMORPHISM
class Dog {
public:
void bark() {
std::cout << "I'm a generic dog\n";
}
};
class Terrier : public Dog {
public:
void bark() {
std::cout << "I'm a terrier\n";
};
};
std::unique_ptr<Dog> dog = std::make_unique<Terrier>();
dog->bark();
POLYMORPHISM
class Dog {
public:
virtual void bark() {
std::cout << "I'm a generic dog\n";
}
virtual ~Dog() = default;
};
class Terrier : public Dog {
public:
void bark() override {
std::cout << "I'm a terrier\n";
};
};
std::unique_ptr<Dog> dog = std::make_unique<Terrier>();
dog->bark();
smart pointers
and inheritance
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
-
protected members
-
using declaration
-
final specifier
-
private & protected inheritance
-
multiple inheritance
-
diamond problem
-
empty base optimization
-
base method hiding problem (shadowing)
-
virtual methods
-
override specifier
-
dynamic type
-
RTTI
-
dynamic_cast
-
typeid
-
vtables
-
-
by value passing problem (slicing)
-
pure virtual function
-
abstract class
misc
friends
nested members
conversion operators
operator overloading
member pointers
-
unions
std optional
std variant
std any
type ereasure
pimpl
enable shared from this with private inheritance
linkage and static (non-member) functions
Smart Pointers and Inheritance
By Jan Bielak
Smart Pointers and Inheritance
A presentation about different ways of taking function parameters and returning values from functions and smart pointers such as std::unique_ptr, std::shared_ptr, std::weak_ptr as well as public inheritance and the protected qualifier, in-class using-declarations, base class member shadowing and the basics of polymorphism. It is presented here: https://www.youtube.com/watch?v=pIj3C6sveUM .
- 684