Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A shared resource for an object

Tags:

c++

Say I have this class called Dog. Every dog has a different name but the same barking voice (which is loaded from a resource file).

class Dog {
public:
    Dog(const string &name) : _name(name) {
        _barkingVoice.load();
    }
    ~Dog() {
        _barkingVoice.free();
    }

    string getName() const { return _name; }
    void bark() { _barkingVoice.play(); }

private:
    string _name;
    VoiceResource _barkingVoice;
};

I want to call _barkingVoice.load() only if the instance of Dog is the first one, and _barkingVoice.free() only if there are no more instances of Dog.

The obvious solution is to set _barkingVoice as static and keep a reference counter of Dog as a data member.

My question is if there's an easier way to do this. Maybe an std implementation or something like that.

like image 262
Pilpel Avatar asked Sep 06 '26 11:09

Pilpel


1 Answers

Make a reusable class to encapsulate the reference counting:

template<class ResourceType, class OwnerType>
class RefCounted {
public:
    RefCounted()          { if (++_refCount == 1) _resource.load(); }
    virtual ~RefCounted() { if (--_refCount == 0) _resource.free(); }
    ResourceType& operator*()  { return  _resource; }
    ResourceType* operator->() { return &_resource; }
private:
    static unsigned _refCount;
    static ResourceType _resource;
};

template<class T, class U> unsigned RefCounted<T, U>::_refCount = 0;
template<class T, class U> T RefCounted<T, U>::_resource;

class Dog {
public:
    Dog(const string &name) : _name(name) { }

    string getName() const { return _name; }
    void bark() { _barkingVoice->play(); }

private:
    string _name;
    RefCounted<VoiceResource, Dog> _barkingVoice;
};

Every template instantiation will have their own _refCount and _resource.

The second template parameter is to handle cases where you instantiate RefCounted with the same ResourceType but want to have separate reference counting for those instantiations. E.g. if you add a Cat class and want it to have its own Refcounted<VoiceResource>:

class Cat {
    // ...
private:
    RefCounted<VoiceResource, Cat> _meowingVoice;
};
like image 106
emlai Avatar answered Sep 08 '26 05:09

emlai



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!