# Efficiency ___ ## Raw pointer ```cpp #include #include struct Data { char tab_[42]; }; int main(void) { constexpr unsigned size = 10u * 1000u * 1000u; std::vector v; v.reserve(size); for (unsigned i = 0; i < size; ++i) { auto p = new Data; v.push_back(std::move(p)); } for (auto p: v) delete p; } ``` ___ ## Unique pointer ```cpp #include #include struct Data { char tab_[42]; }; int main(void) { constexpr unsigned size = 10u * 1000u * 1000u; std::vector> v; v.reserve(size); for (unsigned i = 0; i < size; ++i) { std::unique_ptr p{new Data}; v.push_back(std::move(p)); } } ``` ___ ## Shared pointer ```cpp #include #include struct Data { char tab_[42]; }; int main(void) { constexpr unsigned size = 10u * 1000u * 1000u; std::vector> v; v.reserve(size); for (unsigned i = 0; i < size; ++i) { std::shared_ptr p{new Data}; v.push_back(std::move(p)); } } ``` ___ ## Shared pointer – `make_shared` ```cpp #include #include struct Data { char tab_[42]; }; int main(void) { constexpr unsigned size = 10u * 1000u * 1000u; std::vector> v; v.reserve(size); for (unsigned i = 0; i < size; ++i) { auto p = std::make_shared(); v.push_back(std::move(p)); } } ``` ___ ## Weak pointer ```cpp #include #include struct Data { char tab_[42]; }; int main(void) { constexpr unsigned size = 10u * 1000u * 1000u; std::vector> vs; std::vector> vw; vs.reserve(size); vw.reserve(size); for (unsigned i = 0; i < size; ++i) { std::shared_ptr p{new Data}; std::weak_ptr w{p}; vs.push_back(std::move(p)); vw.push_back(std::move(w)); } } ``` ___ ## Measurements * gcc-4.8.2 * compilation with –std=c++11 –O3 –DNDEBUG * measuring with: * time (real) * htop (mem) * valgrind (allocations count) ___ ## Results | test name | time [s] | allocations | memory [MB] | |:--------------:|:--------:|:-----------:|:-----------:| | raw pointer | 0.54 | 10 000 001 | 686 | | unique pointer | 0.56 | 10 000 001 | 686 | | shared pointer | 1.00 | 20 000 001 | 1072 | | make shared | 0.76 | 10 000 001 | 914 | | weak pointer | 1.28 | 20 000 002 | 1222 | ___ ## Conclusions * RAII * acquire resource in constructor * release resource in destructor * Rule of 5, Rule of 0 * Smart pointers: * std::unique_ptr – primary choice, no overhead, can convert to std::shared_ptr * std::shared_ptr – introduces memory and runtime overhead * std::weak_ptr – breaking cycles, can convert to/from std::shared_ptr * Create smart pointers with std::make_shared() and std::make_unique() * Raw pointer should mean „access only” (no ownership) * Use reference instead of pointers if possible ___ ## Post-work * Transform the list from List.cpp into double-linked list. You should implement: * inserting Nodes at the beginning of the list * searching elements in reverse * Apply proper smart pointers for the reverse direction. * Implement your own unique_ptr. Requirements: * Templatized (should hold a pointer to a template type) * RAII (acquire in constructor, release in destructor) * Copying not allowed * Moving allowed * Member functions: operator*(), operator->(), get(), release(), reset() * Read one of these articles on move semantics: * Semantyka przenoszenia (in Polish) * Move semantics and rvalue references in C++11 (in English)