在这种情况下我应该使用什么智能指针?

时间:2013-04-10 21:04:14

标签: c++ boost smart-pointers

我有一个类ResourceManifest,它从文件中加载3d模型并将它们保存在向量中,然后根据请求将它们移出。也可以从存储中删除缓存的3dmodel,我希望我的其他组件在发生这种情况时能够意识到这一点。这是我现在拥有的,但它不能满足我对属于ResourceManifest类的唯一所有权的意图

    typedef boost::shared_ptr<Model> ModelPtr;

    class ResourceManifest
    {
    public:
        ResourceManifest(IRenderer& renderer);
        ~ResourceManifest();

        ModelPtr LoadModel(const std::string& modelName, const std::string& assetName);
        ModelPtr GetModel(const std::string& modelName);
        void DeleteModel(ModelPtr model);


    private:
        IRenderer& mRenderer;
        std::vector<ModelPtr> mModels;
        IMemoryAllocator& mMemoryAllocator;
    };

在我的第一次尝试中,我将Model保留为shared_ptrs;但结果是,如暗示的那样,它是共享所有权,我只希望ResourceManifest向量内的副本成为所有者。我想要一个智能指针的原因只是能够查询Model是否仍然存在,这是我用原始指针做不到的事情。

我知道weak_ptr,但如果可能,我宁愿避免使用它的语法;如果可能,我想像普通指针一样使用它,就像这样......

ModelPtr modelCube = resourceManifest.GetModel("Cube");

...... later on

if (modelCube)
    modelCube->render();

2 个答案:

答案 0 :(得分:1)

您可以为weak_ptr创建自己的包装器。这是一个简单的,未完成的,可以帮助你入门。

template<typename T>
class weak_ptr2
{
public:
    weak_ptr2(std::shared_ptr<T> const & sp)
        :wp(sp)
    {}

    T & operator*() const { return *(wp.lock()); }
    T * operator->() const { return wp.lock().get(); }
    explicit operator bool() const { return !wp.expired(); }
private:
    std::weak_ptr<T> wp;
};

答案 1 :(得分:1)

解决问题的一个解决方案是使用weak_ptr,但正如我理解你的问题,你不喜欢它的语法。 ResourceManifest :: GetModel将返回一个weak_ptr,你必须使用.lock()才能获得一个shared_ptr到Model,如果.lock()成功,则会产生一个你可以使用的有效shared_ptr。

您在问题中未提及的shared_ptr / weak_ptr方法的另一个问题是,尽管除了weak_ptr之外没有提供任何内容,ResourceManifest实际上并不是模型的所有者。我的意思是没有任何东西阻止ResourceManifest的用户将weak_ptr提升为shared_ptr并保持shared_ptr,从而使其保持活动的时间超过ResourceManifest想要的时间。简而言之,ResourceManifest无法控制模型的生命周期。

你可以做的是发明你自己的智能指针,它只保留原始指针:

MySmartPtr model = manifest.GetModel("foobar");

如果原始指针有效,则实现布尔测试:

if (model)

如果指针有效,您的智能指针可以询问ResourceManifest。如果指针有效,用户可以通过智能指针的解引用运算符使用指针:

  model->render();

这里有一个问题:如果要从多个线程使用智能指针和ResourceManifest,那么

if (model)
  model->render();

成为竞争条件,但由于你的问题没有提及多个主题,我不会为你提供答案......