Let's say I have a class Bitmap
that has a static cache map textures
that holds pointers to all images that have been registered.
class Bitmap {
public:
Bitmap(const std::string &filename);
// ... functionality ...
private:
// ... image data ...
std::string filename;
static std::map<std::string, std::unique_ptr<Bitmap>> images;
}
Is it possible for the constructor of Bitmap
to search the cache for an existing object with the same filename
and then return a reference to that?
I've tried something like
if (images.find(filename) != images.end()) {
*this = images[filename].get();
return;
}
but that doesn't seem to work. Is there a way at all to achieve this effect using the constructor?
CodePudding user response:
By the time you're actually constructing an object, you're already outside the scope of controlling the object's allocation. The constructor is simply there to initialize the object.
One way to achieve this with minimal changes to your code is to make the constructor private and create a static method to perform the create/cache logic.
class Bitmap {
public:
static Bitmap& Get(const std::string &filename);
private:
Bitmap(const std::string &filename)
: filename(filename)
{
std::cout << "Construct " << filename << "\n";
}
std::string filename;
static std::map<std::string, std::unique_ptr<Bitmap>> images;
};
std::map<std::string, std::unique_ptr<Bitmap>> Bitmap::images;
Bitmap& Bitmap::Get(const std::string &filename)
{
auto it = images.find(filename);
if (it == images.end())
{
std::unique_ptr<Bitmap> ptr(new Bitmap(filename));
it = images.insert(std::make_pair(filename, std::move(ptr))).first;
}
return *(it->second);
}
Driver code:
int main()
{
auto a = Bitmap::Get("foo");
auto b = Bitmap::Get("bar");
auto c = Bitmap::Get("foo");
}
Output:
Construct foo
Construct bar
This essentially turns your Bitmap
class into a self-managing cache. If you want to allow both cached and uncached bitmap instances, then you would move the caching stuff to a separate factory class such as BitmapManager
.
CodePudding user response:
The sane way to make it work is to move all data members to a struct, and store a std::shared_ptr
to it in the Bitmap
(and in the static map).