Last active
November 17, 2024 17:16
-
-
Save tolgayilmaz86/00b7d9fb73c9b03b71620619bf9da439 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
/* | |
If you're looking to store any type of object in a container without using ๐๐๐๐* | |
or creating a new hierarchy, ๐๐๐::๐๐๐ข might be a good choice. | |
It can store any type, but retrieving the stored value requires caution, | |
as you need to know the type to use ๐๐๐::๐๐๐ข_๐๐๐๐ effectively. | |
One useful application for this approach is an object storage class that maintains | |
a list of singletons. This class, ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐, | |
offers a ๐๐๐ method that either returns an existing object or creates | |
a new one if it doesnโt exist. Internally, | |
๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ uses a hash map with ๐๐๐::๐๐ข๐๐_๐๐๐๐๐ก as the key and ๐๐๐::๐๐๐ข as the value. | |
Check the code below for more details. | |
The example below depicts a SingletonStorage that is created upon the first request for an object. | |
Note that stored objects should have a copy constructor. | |
However, if a noexcept move constructor is present, it will be used to move the created value into the ๐ ๐ก๐::๐๐๐ฆ. | |
*/ | |
#include <iostream> | |
#include <unordered_map> | |
#include <any> | |
#include <typeindex> | |
#include <memory> | |
#include <stdexcept> | |
#include <mutex> | |
class SingletonStorage { | |
public: | |
// Template method to get or create an instance of the specified type | |
template <typename T> | |
T& get() { | |
std::type_index typeIndex(typeid(T)); | |
// Check if the object already exists | |
auto it = storage.find(typeIndex); | |
if (it != storage.end()) { | |
// Retrieve and cast the stored object | |
return std::any_cast<T&>(it->second); | |
} | |
// Create a new instance if not found | |
// noexcept move constructor will be used, but type should be copieable | |
auto insert = storage.emplace(typeIndex, std::make_any<T>()); | |
// Return a reference | |
return std::any_cast<T&>(insert.first->second); | |
} | |
// Delete copy and assignment operators to ensure singleton behavior | |
SingletonStorage(const SingletonStorage&) = delete; | |
SingletonStorage& operator=(const SingletonStorage&) = delete; | |
static SingletonStorage& instance() { | |
static SingletonStorage instance; | |
return instance; | |
} | |
private: | |
SingletonStorage() = default; | |
std::unordered_map<std::type_index, std::any> storage; // Map of type-indexed singletons | |
}; | |
// Example classes to be managed by SingletonStorage | |
class MyClass1 { | |
public: | |
void display() const { | |
std::cout << "MyClass1 instance\n"; | |
} | |
}; | |
class MyClass2 { | |
public: | |
void show() const { | |
std::cout << "MyClass2 instance\n"; | |
} | |
}; | |
int main() { | |
// Retrieve and use instances of MyClass1 and MyClass2 from SingletonStorage | |
auto& obj1 = SingletonStorage::instance().get<MyClass1>(); | |
auto& obj2 = SingletonStorage::instance().get<MyClass2>(); | |
obj1.display(); // Output: MyClass1 instance | |
obj2.show(); // Output: MyClass2 instance | |
// Retrieve the same instances again to verify singleton behavior | |
auto& sameObj1 = SingletonStorage::instance().get<MyClass1>(); | |
auto& sameObj2 = SingletonStorage::instance().get<MyClass2>(); | |
// The same instances are used, so no new output | |
sameObj1.display(); // Output: MyClass1 instance | |
sameObj2.show(); // Output: MyClass2 instance | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment