#include #include #include #include #include #include #include // 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 pass_through(std::unique_ptr 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 next; }; std::unique_ptr 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(new Node{data, std::move(head)}); } }; int main() { std::cout << "1) Unique ownership semantics demo\n"; { // Create a (uniquely owned) resource std::unique_ptr p = std::make_unique(); // Transfer ownership to `pass_through`, // which in turn transfers ownership back through the return value std::unique_ptr 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 p = std::make_unique(); // 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; 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 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 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 }