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

What smart pointer should I use in this case?

本文关键字:什么 智能 指针 这种情况下 我应该      更新时间:2023-10-16

我有一个类,ResourceManifest,它从文件中加载3d模型,并将它们保存在矢量中,然后按要求分发。也可以从存储中删除缓存的3d模型,我希望我的其他组件在发生这种情况时意识到这一点。这是我现在拥有的,但它不满足我属于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的vector中的副本成为所有者。我想要一个智能指针的原因只是能够查询Model是否仍然存在,这是我不能用原始指针做的事情。

我知道weak_ptr,但我宁愿避免它的语法,如果可能的话;如果可能的话,我想把它当作一个普通的指针来使用,就像这样…

ModelPtr modelCube = resourceManifest.GetModel("Cube");
...... later on
if (modelCube)
    modelCube->render();

解决你的问题的一个解决方案是使用weak_ptr的,但正如我理解你的问题,你不喜欢它的语法。resourceemanifest::GetModel将返回一个weak_ptr,您必须通过.lock()来获得一个shared_ptr到模型,如果.lock()成功,则返回一个有效的shared_ptr,您可以使用它。

你在问题中没有提到的shared_ptr/weak_ptr方法的另一个问题是,尽管ResourceManifest除了weak_ptr之外没有分发任何东西,但它并不是模型的真正所有者。我的意思是,没有什么可以阻止ResourceManifest的用户将weak_ptr提升为shared_ptr并持有shared_ptr,从而使其存活的时间比ResourceManifest想要的更长。简而言之,ResourceManifest失去了对模型生命周期的控制。

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

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

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

if (model)

你的智能指针可以,例如,询问ResourceManifest指针是否有效。如果指针有效,则用户可以通过智能指针的解引用操作符使用该指针:

  model->render();
但是这里有一个问题:如果你的智能指针和ResourceManifest要在多个线程中使用,你的
if (model)
  model->render();

变成了一个竞争条件,但是因为你的问题没有提到多线程,我就不给你答案了。

您可以为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;
};