【问题标题】:What smart pointer should I use in this case?在这种情况下我应该使用什么智能指针?
【发布时间】:2013-04-11 05:47:09
【问题描述】:

我有一个类,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();

【问题讨论】:

  • weak_ptr 就是为这种情况而发明的,您不应该立即忽略它。
  • 如果可能的话,我想模拟它的用法,使其与常规指针完全一样

标签: c++ boost smart-pointers


【解决方案1】:

解决您的问题的一个解决方案是使用weak_ptr,但据我了解您的问题,您不喜欢它的语法。 ResourceManifest::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();

成为竞争条件,但由于您的问题没有提及多个线程,因此我不会为您提供答案...

【讨论】:

  • 不需要多线程。我不明白为什么没有智能指针可以满足我的所有权要求,它肯定也适用于其他地方吗?
  • 由于 shared_ptr/weak_ptr 组合(以及关于不将weak_ptrs提升为share_ptrs的约定)满足您的所有权要求,并且您的要求实际上只是上述组合的语法糖,我并不感到惊讶它不是 C++ 标准的一部分。除了;像我建议的那样的方案通常很容易实现。您还可以使用 weak_ptrs 和 shared_ptrs 作为智能指针的实现细节。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-02
    • 2015-02-04
    • 2018-11-11
    相关资源
    最近更新 更多