Last active
February 24, 2021 06:23
-
-
Save fenbf/0f3d404a57fe78278a2605d45b2ff2b8 to your computer and use it in GitHub Desktop.
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 characters
| // 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)); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment