【问题标题】:Assigning std::shared_ptr分配 std::shared_ptr
【发布时间】:2013-09-08 10:54:41
【问题描述】:

在我的代码中,我有一个动态分配的普通指针

class Texture
{
    //code...
    SDL_Texture* m_texture;
};

我有来自 Texture 类的 Init() 函数分配了 SDL_Texture*,并且析构函数释放了内存。

然而,这被证明是一个问题。我必须使用 shared_ptr,因为我对不同的对象使用相同的纹理,这将被破坏,因此不允许我正确显示它们(在向量中的第一个对象被破坏后,纹理(为所有相同类型的对象共享) ) 不见了)。

所以我决定使用 shared_ptr,但我有一个问题 - 我不知道如何为 shared_ptr 分配一些东西:

//Old code:
m_texture = loadTexture();

//New code:

class Texture
{
   std::shared_ptr<SDL_Texture> m_texture;
};
//code...

m_texture = loadTexture(); // Error! No assignment operator

我试过 .get() 函数,但它是右值,所以我不能给它分配任何东西。有什么想法吗?

提前致谢。

【问题讨论】:

  • 试试.reset()方法
  • loadTexture() 返回什么?
  • 其实我在上面写代码时犯了一个小错误(in post),但没关系。代码看起来像 m_texture.reset(SDL_CreateTextureFromSurface(renderer, loadedSurface)); SDL_CreateTextureFromSurfacce 返回 SDL_Texture* PS。因为我尝试使用 .reset(),所以我这样做了:m_texture.reset(SDL_CreateTextureFromSurface(renderer,loadedSurface));还有甜蜜的模板错误,我完全不知道这是什么意思。对不起,糟糕的评论,但我不知道如何格式化它(还)

标签: c++ pointers c++11 std shared-ptr


【解决方案1】:

您也需要一个自定义删除器:

#include <memory>

// Fake SDL library

typedef void SDL_Texture;

SDL_Texture* SDL_CreateTextureFromSurface(/*SDL_Renderer* , SDL_Surface* */) {
    return 0;
}

void SDL_DestroyTexture(SDL_Texture* texture)
{}

// Shared

typedef std::shared_ptr<SDL_Texture> SharedTexture;

inline SharedTexture make_shared(SDL_Texture* texture) {
    return SharedTexture(texture, SDL_DestroyTexture);
}

int main() {
    SharedTexture texture;
    texture = make_shared(SDL_CreateTextureFromSurface());
}

请注意,C 库:

  • 可以使用不透明类型
  • 有自己的删除功能或正在免费使用

【讨论】:

    【解决方案2】:

    std::shared_ptr 不允许您直接为其分配普通指针。当您考虑时,有很多令人信服的理由来禁止它隐含地发生。首先,shared_ptr 需要分配一个(通常是外部的)引用计数器。例如,考虑以下(假设的)代码:

    std::shared_ptr<A> p1 = obj;
    std::shared_ptr<A> p2 = obj;
    

    当指针超出范围时会发生什么?每个分配都会创建自己的引用计数器,因为p2 无法知道p1 创建的引用计数器。实际上,obj 被删除了两次 - UB。

    首选的解决方案是使用库函数std::make_shared。与包装外部创建的对象相比,它提供了许多好处:

    • 计数器与对象在同一个堆块中创建,因此减少了内存分配的开销,提高了内存一致性
    • 它提供了更高的异常安全性 - 查看 here 以获得关于它避免的问题的良好参考

    另一种选择是从std::enable_shared_from_this 派生由shared_ptr 管理的类。此类对象维护必要的结构作为数据成员,因此保留了make_shared 的第一个好处。此外,以第一个示例中描述的方式初始化shared_ptr 变得有效,因为构造函数/复制赋值运算符可以识别std::enable_shared_from_this 子类并使用内部结构进行簿记,因此p1 和@987654335 @ 将使用相同的引用计数器,存储在 obj 中。

    但有时,就像在这种情况下,不可能使用上述任何策略。如果你真的需要直接设置一个shared_ptr,有一个方法可以做到——reset()。但是,请谨慎使用它,并确保尽快将指针包装在shared_ptr 中,然后让它管理它。特别是我认为将此类资源的创建封装在一个方法中并且从不将包装的指针暴露在它之外是一种很好的做法。

    【讨论】:

    • ''m_texture = std::make_shared( SDL_CreateTextureFromSurface(renderer, loadedSurface ) );'' 我决定试试 ''std::make_shared''。我按照我发布的那样做了,但这对我不起作用。它再次显示 STL 错误。它说它不能在不完整的 SDL_Texture 类型上使用运算符 sizeof(如果我正确理解了这个错误)
    猜你喜欢
    • 2016-06-19
    • 1970-01-01
    • 2017-08-10
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 2014-03-25
    相关资源
    最近更新 更多