分配std :: shared_ptr

时间:2013-09-08 10:54:41

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

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

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

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

然而,事实证明这是一个问题。我不得不使用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()函数,但它是rvalue,所以我不能给它分配任何东西。有什么想法吗?

提前致谢。

2 个答案:

答案 0 :(得分:4)

您也需要自定义删除器:

#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库:

  • 可以使用opaque类型
  • 有自己的删除功能或使用免费

答案 1 :(得分:3)

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查看它避免的问题的良好参考

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

但是,有时候,在这种情况下,不可能使用上述任何策略。如果您确实需要直接设置reset(),则有一种方法可以执行此操作 - shared_ptr。但请谨慎使用它,并确保尽快将指针包裹在{{1}}中,然后让它管理它。特别是我认为良好的做法是在方法中封装这种资源的创建,并且永远不要将包装的指针暴露在它之外。