C++ Talk Tipp & copy_on_write Code (dies ist keine Frage)
-
Hi!
Inspiriert von Sean Parent's Vortrag "Value Semantics and Concepts-based Polymorphism", den ich übrigens empfehlen kann, habe ich mich just-4-fun mal dran gesetzt, einen copy_on_write-Wrapper zu basteln, so wie er im Vortrag verwendet wurde. Das Ding ist mit Hilfe von shared_ptr und make_shared auch relativ easy umzusetzen und könnte hier ja irgendjemandem nutzen oder einen Denkanstoß verpassen.
Warum wieso weshalb copy_on_write? --> Wertesemantik mit "Sharing" als Optimierung, effizientes Kopieren und Moven ist unabhängig von T möglich.
copy_on_write.hpp:
#ifndef COPY_ON_WRITE_HPP_INCLUDED #define COPY_ON_WRITE_HPP_INCLUDED #include <cassert> #include <type_traits> #include <utility> #include <memory> enum cow_dont_initialize_tag { cow_dont_initialize }; /// Copy-On-Write wrapper for a T object. It supports a "null state" /// (you have to ask for it via an explicit std::move or the /// cow_dont_initialize constructor parameter, though!). template<class T> class copy_on_write { public: /// Construct copy_on_write object without initializing a T object. /// The function initialized() will return false and you're not allowed /// to access the T object (because it doesn't exist!). explicit copy_on_write(cow_dont_initialize_tag) noexcept : ptr(nullptr) {} /// Construct copy_on_write object which holds a default-constructed T object copy_on_write() { static const std::shared_ptr<T> default_constructed = std::make_shared<T>(); this->ptr = default_constructed; } /// Construct copy_on_write object to store a given T object initialized /// with an initializer_list. template<class E ,class=typename std::enable_if<( std::is_constructible<T,std::initializer_list<E>>::value )>::type > copy_on_write(std::initializer_list<E> il) : ptr(std::make_shared<T>(il)) {} /// Construct copy_on_write object to hold a T object constructed by /// forwarding parameters template<class Arg, class...Args ,class=typename std::enable_if<( std::is_constructible<T,Arg,Args...>::value && ( sizeof...(Args)>0 || // exclude copy/move ctor for copy_on_write !std::is_same<typename std::decay<Arg>::type,copy_on_write<T>>::value ) )>::type > copy_on_write(Arg&& arg, Args&&...args) : ptr(std::make_shared<T>( std::forward<Arg>(arg), std::forward<Args>(args)... )) {} /// copy ctor copy_on_write(copy_on_write const& x) noexcept : ptr(x.ptr) {} /// move ctor copy_on_write(copy_on_write && x) noexcept : ptr(std::move(x.ptr)) {} // assignment copy_on_write& operator=(copy_on_write temp) noexcept { this->swap(temp); return *this; } void swap(copy_on_write& that) noexcept { this->ptr.swap(that.ptr); } friend void swap(copy_on_write& a, copy_on_write& b) noexcept { a.swap(b); } // returns true if and only if this object owns an initialized T object bool initialized() const noexcept { return ptr != nullptr; } // destroys the owned T object void destroy() noexcept { ptr.reset(nullptr); } explicit operator bool() const noexcept { return initialized(); } // read access ... T const& read() const noexcept{ assert(initialized()); return *ptr; } T const& operator*() const noexcept { assert(initialized()); return *ptr; } T const* operator->() const noexcept { assert(initialized()); return ptr.get(); } // write access ... T& write() { assert(initialized()); if (!ptr.unique()) uniqify(); assert(ptr.unique()); return *ptr; } private: std::shared_ptr<T> ptr; void uniqify(); }; template<class T> void copy_on_write<T>::uniqify() { copy_on_write tmp (this->read()); this->swap(tmp); } #endifSimples, etwas realitätsfernes Beispiel:
#include <cassert> #include <vector> #include "copy_on_write.hpp" using namespace std; int main() { copy_on_write<vector<int>> x = {2,3,5,7,11}; copy_on_write<vector<int>> y = x; assert( &x.read() == &y.read() ); y.write()[2] += 10; assert( &x.read() != &y.read() ); }(kompiliert mit G++ 4.6.1 und C++0x-Schalter)
-
krümelkacker schrieb:
Inspiriert von Sean Parent's Vortrag "Value Semantics and Concepts-based Polymorphism"
Gibts das auch als Text? Ich kann mit Videos nichts anfangen.
-
Ja:
https://github.com/boostcon/cppnow_presentations_2012/tree/master/fri/value_semanticsDa gibt's sogar Quellcode. Allerdings hat Sean Parent hier nicht erkannt, dass man sich das Leben da mit shared_ptr für die copy_on_write-Implementierung etwas einfacher machen kann. Dann erübrigt sich das auch mit der thread-sicheren Referenzzählung, die ja in shared_ptr schon eingebaut ist.
