Last active
May 9, 2023 20:12
-
-
Save PurityLake/2ebd94d90038571356d2e1c61ae8da5c to your computer and use it in GitHub Desktop.
A sample of using Empty Base Object Optimisation using a custom simplified unique_ptr implementation
This file contains 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
#pragma once | |
#include <iostream> | |
// T1 should be a stateless class that has only one member function | |
// T2 can be any noexcept constructible class | |
template <class T1, class T2> | |
// We inherit from T1 to provide the functionality of T1 without | |
// incurring any additional memory | |
class SimpleCompressedPair : T1 | |
{ | |
public: | |
T2 _t2; | |
explicit SimpleCompressedPair(T2 val) : _t2(val) { } | |
// This class can be cast to an object of T1 as it inherits | |
// from it | |
constexpr T1& getFirst() noexcept { | |
return *this; | |
} | |
// This class can be cast to an object of T1 as it inherits | |
// from it | |
constexpr const T1& getFirst() const noexcept { | |
return *this; | |
} | |
}; | |
// This is used to free the memory in out unique_ptr | |
template<typename T> | |
struct DefaultDeleter | |
{ | |
void operator()(T* ptr) { delete ptr; } | |
}; | |
template<typename T, class Deleter = DefaultDeleter<T>> | |
class uniquer_ptr | |
{ | |
public: | |
constexpr uniquer_ptr() noexcept : MyPair(nullptr) { } | |
constexpr uniquer_ptr(T* ptr) noexcept : MyPair(ptr) { } | |
uniquer_ptr(const uniquer_ptr&) = delete; | |
~uniquer_ptr() noexcept | |
{ | |
if (MyPair._t2) { | |
MyPair.getFirst()(MyPair._t2); | |
std::cout << "HERE" << std::endl; | |
} | |
} | |
T* operator->() const noexcept { return MyPair._t2; } | |
T& operator*() const noexcept { return *MyPair._t2; } | |
private: | |
// Using this we not only store the memory required to hold the T* | |
SimpleCompressedPair<Deleter, T*> MyPair; | |
}; | |
template<typename T, class Deleter = DefaultDeleter<T>> | |
class uniquer_ptr_but_fatter | |
{ | |
public: | |
constexpr uniquer_ptr_but_fatter() noexcept : ptr(nullptr) { } | |
constexpr uniquer_ptr_but_fatter(T* ptr) noexcept : ptr(ptr), d() { } | |
constexpr uniquer_ptr_but_fatter(T* ptr, Deleter d) noexcept : ptr(ptr), d(d) { } | |
constexpr uniquer_ptr_but_fatter(T* ptr, Deleter&& d) noexcept : ptr(ptr), d(std::move(d)) { } | |
uniquer_ptr_but_fatter(const uniquer_ptr_but_fatter&) = delete; | |
~uniquer_ptr_but_fatter() noexcept | |
{ | |
if (ptr) { | |
d(ptr); | |
} | |
} | |
T* operator->() const noexcept { return ptr; } | |
T& operator*() const noexcept { return *ptr; } | |
private: | |
// using this d is of size 1 | |
// t is of size 8 | |
// total of 9 bytes but is 8 byte aligned so becomes 16 bytes | |
Deleter d; | |
T* ptr; | |
}; | |
int main(void) { | |
uniquer_ptr<int> ptr(new int(3)); | |
std::cout << sizeof(ptr) << std::endl; // 8 | |
uniquer_ptr_but_fatter<int> fatptr(new int(3)); | |
std::cout << sizeof(fatptr) << std::endl; //// 16 | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment