Home > Blockchain >  Can a C constructor return a pointer to a cached version of an identical object?
Can a C constructor return a pointer to a cached version of an identical object?

Time:11-30

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).

  • Related