/* # unique_ptr Sample use case: - you want a dynamic array a dynmically allocated derived class - thus you have to use pointers for polymorphism. Otherwise objects can have different sizes, and arrays can't be used. - how to prevent memory leaks? http://en.cppreference.com/w/cpp/memory/unique_ptr unique_ptr may incur an extra dereferece cost, but it is usually well worth it. In Java, everything can be though as a smart pointer (shared), so using this is still more efficient than Java, since C++ can know the exact lifetime of objects, and release them immediately when they are done. */ #include "common.hpp" class Base { public: static int count; Base(int i) : i(i) { count++; } ~Base() { count--; } int i; }; int Base::count = 0; /* No memory leaked. Destructors called. */ void unique_ptr_test() { std::vector<std::unique_ptr<Base>> bases; for (int i = 0; i < 10; ++i) { bases.push_back(std::unique_ptr<Base>(new Base(i))); } } /* Memory leak. Destructors never called. */ void raw_ptr_test() { std::vector<Base *> bases; for (int i = 0; i < 10; ++i) { bases.push_back(new Base(i)); } } void manual_ptr_test() { std::vector<Base *> bases; for (int i = 0; i < 10; ++i) { bases.push_back(new Base(i)); } for (auto base : bases) { delete base; } } // Create unique pointer dynamically, // and transfers ownershipt to caller. std::unique_ptr<Base> return_unique_ptr() { return std::unique_ptr<Base>(new Base(1)); } int main() { /* Basic example. */ assert(Base::count == 0); unique_ptr_test(); assert(Base::count == 0); raw_ptr_test(); assert(Base::count == 10); manual_ptr_test(); assert(Base::count == 10); // ERROR: Convert to raw pointer. // Not possible, the cast operator is not defined. { std::unique_ptr<int> p(new int); //int *raw = p; } // Copy constructor is deleted. // This is what imposes uniqueness. { std::unique_ptr<int> p(new int); // ERROR. //std::unique_ptr<int> p2(p); // Consequence: for loops over vectors must use references &. // http://stackoverflow.com/questions/20292682/iterating-through-vectorunique-ptrmytype-using-c11-for-loops { std::vector<std::unique_ptr<int>> is; for (auto& i : is) {} // ERROR. //for (auto i : is) {} } // Must move glvalues. // http://stackoverflow.com/questions/3283778/why-can-i-not-push-back-a-unique-ptr-into-a-vector { std::vector<std::unique_ptr<int>> is; std::unique_ptr<int> i(new int(1)); is.push_back(std::move(i)); assert(*is.back() == 1); // Without intermediate variable, we don't need to move, because it is an rvalue, // and unique_ptr does have an move constructor. is.push_back(std::unique_ptr<int>(new int(2))); assert(*is.back() == 2); // Analogously, must move containers instead of copy. { std::vector<std::unique_ptr<int>> is; is.push_back(std::unique_ptr<int>(new int(1))); //std::vector<std::unique_ptr<int>> is2(is); std::vector<std::unique_ptr<int>> is2(std::move(is)); assert(*(is2.front()) == 1); } } } /* # reset Explicit destruction of pointer. Equivalent to `delete`. http://stackoverflow.com/questions/25609457/unique-ptr-explicit-delete */ { Base::count = 0; std::unique_ptr<Base> p = std::unique_ptr<Base>(new Base(1)); assert(Base::count == 1); p.reset(); assert(Base::count == 0); } /* # unique_ptr function argments - transfering ownership TODO - use raw pointeres on the interface, and convert it to unique_ptr inside callee - if you already have an unique_ptr, release() it - this allows you to not tie down to a specific smart pointer on the function interface - use unique_ptr on interface and move on caller. - Advantage: unique_ptr on interface documents ownership transfer, and prevents callee from passing non new pointer to it by mistake. - TODO for not transfering ownership: - `const & std::unique_ptr<T>` - `get()`. Simple and efficient. But how to use it for containers like `vector<std::unique_ptr>`? - `T&` on function, `*t` on caller. Looks good! - http://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-functionhttp://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function - http://stackoverflow.com/questions/11277249/how-to-pass-stdunique-ptr-around */ { } // Return unique_ptr from function. { { Base::count = 0; auto base = return_unique_ptr(); assert(Base::count == 1); assert(base->i == 1); } assert(Base::count == 0); } #if __cplusplus >= 201402L // # make_unique // Does new and puts it inside unique_ptr. Very convenient. { { Base::count = 0; auto base = std::make_unique<Base>(1); assert(Base::count == 1); assert(base->i == 1); } assert(Base::count == 0); } #endif }