Last active
February 24, 2021 06:23
-
-
Save fenbf/0f3d404a57fe78278a2605d45b2ff2b8 to your computer and use it in GitHub Desktop.
Revisions
-
fenbf revised this gist
Apr 26, 2016 . 1 changed file with 61 additions and 24 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,17 +5,29 @@ #include <iostream> #include <memory> #include <functional> #include <cassert> // This class cannot be changed, might come from 3rd party library // to delete it completely you need to call ReleaseElements first! class LegacyList { public: LegacyList() { s_refCounter++; } ~LegacyList() { s_refCounter--; } LegacyList(const LegacyList&) { s_refCounter++; } LegacyList & operator= ( const LegacyList & ) { s_refCounter++; return *this; } void Add(const std::string& str ) { } void Remove(const std::string& str ) { } void ReleaseElements() { } static int GetGlobalObjectRefCount() { return s_refCounter; } private: static int s_refCounter; }; int LegacyList::s_refCounter = 0; // old style Class, with explicit new/delete/raw pointers class WordCache { public: @@ -87,30 +99,19 @@ class ModernSharedWordCache { std::shared_ptr<LegacyList> m_pList; }; void TestOldWay() { WordCache myTestClass; LegacyList* pList = new LegacyList(); // fill the list... myTestClass.UpdateCache(pList); LegacyList* pList2 = new LegacyList(); // fill the list myTestClass.UpdateCache(pList2); } void TestUniqueModernWay() { ModernWordCache myModernClass; // whe nunique_legacylist_ptr uses a function, then we have to pass it in constructor // ModernWordCache::unique_legacylist_ptr pUniqueList(new LegacyList(), &DeleteLegacyList); @@ -121,10 +122,46 @@ int main() //ModernWordCache::unique_legacylist_ptr pUniqueList2(new LegacyList(), &DeleteLegacyList); ModernWordCache::unique_legacylist_ptr pUniqueList2(new LegacyList()); myModernClass.UpdateCache(std::move(pUniqueList2)); } void TestSharedModernWay() { ModernSharedWordCache mySharedClass; mySharedClass.UpdateCache(std::shared_ptr<LegacyList>(new LegacyList(), LegacyListDeleterFunctor())); mySharedClass.UpdateCache(std::shared_ptr<LegacyList>(new LegacyList(), DeleteLegacyList)); // simple example with custom deleter for <int> std::shared_ptr<int> pIntPtr(new int(10), [](int *pi) { delete pi; }); } int main() { std::cout << "sizeof(int*) = " << sizeof(int*) << '\n'; // size of unique_ptr will be 4 or 8 bytes std::cout << "sizeof(std::unique_ptr<LegacyList>) = " << sizeof(std::unique_ptr<LegacyList>) << '\n'; // std::function is a bit heavy, around 32 bytes! (on x64) std::cout << "sizeof(std::function<void (LegacyList*)>) = " << sizeof(std::function<void (LegacyList*)>) << '\n'; std::cout << "sizeof(unique_legacylist_ptr_stdfunc) = " << sizeof(ModernWordCache::unique_legacylist_ptr_stdfunc) << '\n'; // with normal function pointer we have two pointers to store, so 8 or 16 bytes std::cout << "sizeof(unique_legacylist_ptr_function) = " << sizeof(ModernWordCache::unique_legacylist_ptr_function) << '\n'; // if we use stateless functor then the compiler will probably use Empty Base Class optimization and thus we use only 8 bytes(like normal unique_ptr) !! std::cout << "sizeof(unique_legacylist_ptr_functor) = " << sizeof(ModernWordCache::unique_legacylist_ptr_functor) << '\n'; // shared_ptr does not include deleter in type definition, size is always the same std::cout << "sizeof(std::shared_ptr<LegacyList>) = " << sizeof(std::shared_ptr<LegacyList>) << '\n'; auto IntDel = [](int *p) { delete p; }; std::cout << "sizeof(std::unique_ptr<int, decltype(IntDel)>) = " << sizeof(std::unique_ptr<int, decltype(IntDel)>) << '\n'; assert(LegacyList::GetGlobalObjectRefCount() == 0); TestOldWay(); assert(LegacyList::GetGlobalObjectRefCount() == 0); assert(LegacyList::GetGlobalObjectRefCount() == 0); TestUniqueModernWay(); assert(LegacyList::GetGlobalObjectRefCount() == 0); assert(LegacyList::GetGlobalObjectRefCount() == 0); TestSharedModernWay(); assert(LegacyList::GetGlobalObjectRefCount() == 0); } -
fenbf revised this gist
Apr 19, 2016 . 1 changed file with 25 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -75,17 +75,31 @@ class ModernWordCache { unique_legacylist_ptr m_pList; }; // Modern version that uses shared_ptr class ModernSharedWordCache { public: void UpdateCache(std::shared_ptr<LegacyList> pInputList) { m_pList = pInputList; // do something with the list... } private: std::shared_ptr<LegacyList> m_pList; }; int main() { // size of unique_ptr will be 4 or 8 bytes std::cout << "sizeof(std::unique_ptr<LegacyList>) = " << sizeof(std::unique_ptr<LegacyList>) << '\n'; // std::function is a bit heavy, around 32 bytes! (on x64) std::cout << "sizeof(std::function<void (LegacyList*)>) = " << sizeof(std::function<void (LegacyList*)>) << '\n'; std::cout << "sizeof(unique_legacylist_ptr_stdfunc) = " << sizeof(ModernWordCache::unique_legacylist_ptr_stdfunc) << '\n'; // with normal function pointer we have two pointers to store, so 8 or 16 bytes std::cout << "sizeof(unique_legacylist_ptr_function) = " << sizeof(ModernWordCache::unique_legacylist_ptr_function) << '\n'; // if we use stateless functor then the compiler will probably use Empty Base Class optimization and thus we use only 8 bytes(like normal unique_ptr) !! std::cout << "sizeof(unique_legacylist_ptr_functor) = " << sizeof(ModernWordCache::unique_legacylist_ptr_functor) << '\n'; // shared_ptr does not include deleter in type definition, size is always the same: two pointers: the actual data and ptr to control block std::cout << "sizeof(std::shared_ptr<LegacyList>) = " << sizeof(std::shared_ptr<LegacyList>) << '\n'; // // Old way @@ -107,4 +121,10 @@ int main() //ModernWordCache::unique_legacylist_ptr pUniqueList2(new LegacyList(), &DeleteLegacyList); ModernWordCache::unique_legacylist_ptr pUniqueList2(new LegacyList()); myModernClass.UpdateCache(std::move(pUniqueList2)); // // Modern Waywith shared_ptr // ModernSharedWordCache mySharedClass; mySharedClass.UpdateCache(std::shared_ptr<LegacyList>(new LegacyList(), LegacyListDeleterFunctor())); } -
fenbf created this gist
Apr 17, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,110 @@ // smart_ptr_deleters.cpp // shows how to use custom deleters with unique_ptr and shared_ptr // Bartlomiej Filipek, April 2016, bfilipek.com #include <iostream> #include <memory> #include <functional> // This class cannot be changed, might come from 3rd party library // to delete it completely you need to call ReleaseElements first! class LegacyList { public: void Add(const std::string& str ) { } void Remove(const std::string& str ) { } void ReleaseElements() { } }; // old style Class, with explicit new/delete/raw pointers class WordCache { public: WordCache() { m_pList = nullptr; } ~WordCache() { ClearCache(); } void UpdateCache(LegacyList *pInputList) { ClearCache(); m_pList = pInputList; if (m_pList) { // do something with the list... } } private: void ClearCache() { if (m_pList) { m_pList->ReleaseElements(); delete m_pList; m_pList = nullptr; } } LegacyList *m_pList; // owned by the object }; // stateless functor struct LegacyListDeleterFunctor { void operator()(LegacyList* p) { p->ReleaseElements(); delete p; std::cout << "LegacyListDeleterFunctor..." << std::endl; } }; // normal free function used to delete LegacyList void DeleteLegacyList(LegacyList* p) { p->ReleaseElements(); delete p; std::cout << "DeleteLegacyList function..." << std::endl; } // Modern version of the cache, we use std::unique_ptr with custom deleter to handle deletion of LegacyList // we can remove default constructor and destructor, since unique_ptr will do this for us // also we could remove ClearCache method (since it was only for conveniance) class ModernWordCache { public: // different options for custom deleters using unique_legacylist_ptr_stdfunc = std::unique_ptr<LegacyList, std::function<void (LegacyList*)>>; using unique_legacylist_ptr_functor = std::unique_ptr<LegacyList, LegacyListDeleterFunctor>; using unique_legacylist_ptr_function = std::unique_ptr<LegacyList, void (*)(LegacyList *)>; using unique_legacylist_ptr = unique_legacylist_ptr_functor; public: void UpdateCache(unique_legacylist_ptr pInputList) { m_pList = std::move(pInputList); // do something with the list... } private: //unique_legacylist_ptr m_pList { nullptr, &DeleteLegacyList }; unique_legacylist_ptr m_pList; }; int main() { // size of unique_ptr will be 4 or 8 bytes std::cout << "sizeof(std::unique_ptr<LegacyList>) = " << sizeof(std::unique_ptr<LegacyList>) << std::endl; // std::function is a bit heavy, around 32 bytes! (on x64) std::cout << "sizeof(std::function<void (LegacyList*)>) = " << sizeof(std::function<void (LegacyList*)>) << std::endl; std::cout << "sizeof(unique_legacylist_ptr_stdfunc) = " << sizeof(ModernWordCache::unique_legacylist_ptr_stdfunc) << std::endl; // with normal function pointer we have two pointers to store, so 8 or 16 bytes std::cout << "sizeof(unique_legacylist_ptr_function) = " << sizeof(ModernWordCache::unique_legacylist_ptr_function) << std::endl; // if we use stateless functor then the compiler will probably use Empty Base Class optimization and thus we use only 8 bytes(like normal unique_ptr) !! std::cout << "sizeof(unique_legacylist_ptr_functor) = " << sizeof(ModernWordCache::unique_legacylist_ptr_functor) << std::endl; // // Old way // WordCache myTestClass; LegacyList* pList = new LegacyList(); myTestClass.UpdateCache(pList); // // Modern Way // ModernWordCache myModernClass; // whe nunique_legacylist_ptr uses a function, then we have to pass it in constructor // ModernWordCache::unique_legacylist_ptr pUniqueList(new LegacyList(), &DeleteLegacyList); // when nunique_legacylist_ptr uses a functor, functor object is created by default... ModernWordCache::unique_legacylist_ptr pUniqueList(new LegacyList()); myModernClass.UpdateCache(std::move(pUniqueList)); //ModernWordCache::unique_legacylist_ptr pUniqueList2(new LegacyList(), &DeleteLegacyList); ModernWordCache::unique_legacylist_ptr pUniqueList2(new LegacyList()); myModernClass.UpdateCache(std::move(pUniqueList2)); }