You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
3.3 KiB
131 lines
3.3 KiB
2 months ago
|
#include <cassert>
|
||
|
#include <cstdio>
|
||
|
#include <fstream>
|
||
|
#include <iostream>
|
||
|
#include <locale>
|
||
|
#include <memory>
|
||
|
#include <stdexcept>
|
||
|
|
||
|
// helper class for runtime polymorphism demo below
|
||
|
struct B
|
||
|
{
|
||
|
virtual ~B() = default;
|
||
|
|
||
|
virtual void bar() { std::cout << "B::bar\n"; }
|
||
|
};
|
||
|
|
||
|
struct D : B
|
||
|
{
|
||
|
D() { std::cout << "D::D\n"; }
|
||
|
~D() { std::cout << "D::~D\n"; }
|
||
|
|
||
|
void bar() override { std::cout << "D::bar\n"; }
|
||
|
};
|
||
|
|
||
|
// a function consuming a unique_ptr can take it by value or by rvalue reference
|
||
|
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
|
||
|
{
|
||
|
p->bar();
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
// helper function for the custom deleter demo below
|
||
|
void close_file(std::FILE* fp)
|
||
|
{
|
||
|
std::fclose(fp);
|
||
|
}
|
||
|
|
||
|
// unique_ptr-based linked list demo
|
||
|
struct List
|
||
|
{
|
||
|
struct Node
|
||
|
{
|
||
|
int data;
|
||
|
std::unique_ptr<Node> next;
|
||
|
};
|
||
|
|
||
|
std::unique_ptr<Node> head;
|
||
|
|
||
|
~List()
|
||
|
{
|
||
|
// destroy list nodes sequentially in a loop, the default destructor
|
||
|
// would have invoked its `next`'s destructor recursively, which would
|
||
|
// cause stack overflow for sufficiently large lists.
|
||
|
while (head)
|
||
|
{
|
||
|
auto next = std::move(head->next);
|
||
|
head = std::move(next);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void push(int data)
|
||
|
{
|
||
|
head = std::unique_ptr<Node>(new Node{data, std::move(head)});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int main()
|
||
|
{
|
||
|
std::cout << "1) Unique ownership semantics demo\n";
|
||
|
{
|
||
|
// Create a (uniquely owned) resource
|
||
|
std::unique_ptr<D> p = std::make_unique<D>();
|
||
|
|
||
|
// Transfer ownership to `pass_through`,
|
||
|
// which in turn transfers ownership back through the return value
|
||
|
std::unique_ptr<D> q = pass_through(std::move(p));
|
||
|
|
||
|
// p is now in a moved-from 'empty' state, equal to nullptr
|
||
|
assert(!p);
|
||
|
}
|
||
|
|
||
|
std::cout << "\n" "2) Runtime polymorphism demo\n";
|
||
|
{
|
||
|
// Create a derived resource and point to it via base type
|
||
|
std::unique_ptr<B> p = std::make_unique<D>();
|
||
|
|
||
|
// Dynamic dispatch works as expected
|
||
|
p->bar();
|
||
|
}
|
||
|
|
||
|
std::cout << "\n" "3) Custom deleter demo\n";
|
||
|
std::ofstream("demo.txt") << 'x'; // prepare the file to read
|
||
|
{
|
||
|
using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>;
|
||
|
unique_file_t fp(std::fopen("demo.txt", "r"), &close_file);
|
||
|
if (fp)
|
||
|
std::cout << char(std::fgetc(fp.get())) << '\n';
|
||
|
} // `close_file()` called here (if `fp` is not null)
|
||
|
|
||
|
std::cout << "\n" "4) Custom lambda-expression deleter and exception safety demo\n";
|
||
|
try
|
||
|
{
|
||
|
std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
|
||
|
{
|
||
|
std::cout << "destroying from a custom deleter...\n";
|
||
|
delete ptr;
|
||
|
});
|
||
|
|
||
|
throw std::runtime_error(""); // `p` would leak here if it were a plain pointer
|
||
|
}
|
||
|
catch (const std::exception&)
|
||
|
{
|
||
|
std::cout << "Caught exception\n";
|
||
|
}
|
||
|
|
||
|
std::cout << "\n" "5) Array form of unique_ptr demo\n";
|
||
|
{
|
||
|
std::unique_ptr<D[]> p(new D[3]);
|
||
|
} // `D::~D()` is called 3 times
|
||
|
|
||
|
std::cout << "\n" "6) Linked list demo\n";
|
||
|
{
|
||
|
List wall;
|
||
|
const int enough{1'000'000};
|
||
|
for (int beer = 0; beer != enough; ++beer)
|
||
|
wall.push(beer);
|
||
|
|
||
|
std::cout << enough << " bottles of beer on the wall...\n";
|
||
|
} // destroys all the beers
|
||
|
}
|