Skip to content

Instantly share code, notes, and snippets.

@fenbf
Last active February 24, 2021 06:23
Show Gist options
  • Select an option

  • Save fenbf/0f3d404a57fe78278a2605d45b2ff2b8 to your computer and use it in GitHub Desktop.

Select an option

Save fenbf/0f3d404a57fe78278a2605d45b2ff2b8 to your computer and use it in GitHub Desktop.
// 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