To create safe object lifetimes in C++, we always attach the lifetime of one object to that of something else
// myintpointer.h
class MyIntPointer {
public:
// This is the constructor
MyIntPionter(int* value);
// This is the destructor
~MyIntPointer() noexcept;
int* GetValue();
private:
int* value_;
};
// myintpointer.cpp
#include "myintpointer.h"
MyIntPointer::MyIntPointer(int* value): value_{value} {}
int* MyIntPointer::GetValue() {
return value_
}
MyIntPointer::~MyIntPointer() noexcept {
// Similar to C's free function.
delete value_;
}
Don't use the new / delete keyword in your own code
We are showing for demonstration purposes
void fn() {
// Similar to C's malloc
MyIntPointer p{new int{5}};
// Copy the pointer;
MyIntPointer q{p.GetValue()};
// p and q are both now destructed.
// What happens?
}
Type | Shared ownership | Take ownership |
---|---|---|
std::unique_ptr<T> | No | Yes |
raw pointers | No | No |
std::shared_ptr<T> | Yes | Yes |
std::weak_ptr<T> | No | No |
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int> up1{new int};
std::unique_ptr<int> up2 = up1; // no copy constructor
std::unique_ptr<int> up3;
up3 = up2; // no copy assignment
up3.reset(up1.release()); // OK
std::unique_ptr<int> up4 = std::move(up3); // OK
std::cout << up4.get() << "\n";
std::cout << *up4 << "\n";
std::cout << *up1 << "\n";
}
Can we remove "new" completely?
#include <memory>
#include <experimental/memory>
#include <iostream>
int main() {
int *i = new int;
std::unique_ptr<int> up1{i};
*up1 = 5;
std::cout << *up1 << "\n";
std::experimental::observer_ptr<int> op1{i};
*op1 = 6;
std::cout << *op1 << "\n";
up1.reset();
std::cout << *op1 << "\n";
}
#include <memory>
#include <experimental/memory>
#include <iostream>
int main() {
// 1 - Worst
int *i = new int;
std::unique_ptr<std::string> up1{i};
// 2 - Not good
std::unique_ptr<std::string> up2{new std::string{"Hello"}};
// 3 - Good
std::unique_ptr<std::string> up3 = make_unique<std::string>("Hello");
std::cout << *up3 << "\n";
std::cout << *(up3.get()) << "\n";
std::cout << up3->size();
}
#include <memory>
#include <iostream>
int main() {
int* i = new int;
*i = 5;
std::shared_ptr<int> x{i};
std::shared_ptr<int> y = x; // Both now own the memory
std::cout << "use count: " << x.use_count() << "\n";
std::cout << "value: " << *x << "\n";
x.reset(); // Memory still exists, due to y.
std::cout << "use count: " << y.use_count() << "\n";
std::cout << "value: " << *y << "\n";
y.reset(); // Deletes the memory, since
// no one else owns the memory
std::cout << "use count: " << x.use_count() << "\n";
std::cout << "value: " << *y << "\n";
}
Can we remove "new" completely?
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> x = std::make_shared<int>(1);
std::weak_ptr<int> wp = x; // x owns the memory
{
std::shared_ptr<int> y = wp.lock(); // x and y own the memory
if (y) {
// Do something with y
std::cout << "Attempt 1: " << *y << '\n';
}
} // y is destroyed. Memory is owned by x
x.reset(); // Memory is deleted
std::shared_ptr<int> z = wp.lock(); // Memory gone; get null ptr
if (z) {
// will not execute this
std::cout << "Attempt 2: " << *z << '\n';
}
}