【问题标题】:Delete std::shared_ptr without destroying the managed object?删除 std::shared_ptr 而不破坏托管对象?
【发布时间】:2015-03-08 02:40:51
【问题描述】:

我处于以下情况:

struct container {
    data* ptr;
};

void someFunc(container* receiver /* wants to be filled */) {
    auto myData = createData(); // returns shared_ptr<data>
    receiver->ptr = myData.get();
}

生成数据的函数和接收数据的对象是两个不同库的一部分,我无法修改它们的源代码。我必须处理这些数据类型,对此我无能为力。

所以我必须实现一个获取一些数据的函数,然后将指向该数据的指针传递给一个对象。我的问题是创建我的数据的函数返回一个 shared_ptr 实例给它。需要数据的对象只会接受指向它的原始指针。

如您所见,我在shared_ptr 上调用get() 以获取原始指针并将其传递给接收对象。如果我没记错的话,shared_ptr 会在超出范围时减少引用计数。所以在这种情况下,这意味着它会在函数返回后立即销毁我的数据,因为引用计数将达到 0。

那么我怎样才能在不破坏托管对象的情况下摆脱shared_ptr 实例呢?我将数据传递给的对象(为简单起见,用“容器”结构说明)确实负责其析构函数内部的内存清理,因此我不需要任何引用计数或类似的东西。我不想再监视分配的数据(接收指向它的指针的对象除外)。我想摆脱shared_ptr,只有一个指向分配数据的原始指针,我可以将它传递给接收对象。

这可能吗?

【问题讨论】:

  • 有什么特殊原因不能让容器接受共享指针吗?它们的全部意义在于您无需担心生命​​周期管理。如果不需要,不要使用原始指针。
  • @aruisdante 我知道,我尽可能在所有项目中使用智能指针。但在这种情况下,createDatacontainer 都是某些库的一部分,我无法修改(即两个不同的库。这就是为什么它们不会说相同的“语言”)。
  • 复制数据。您有两件事需要控制数据的生命周期,这需要两个副本。
  • @DavidSchwartz 虽然它不是最有效的,但它可能是最易读、可维护和最安全的方式。

标签: c++ shared-ptr smart-pointers


【解决方案1】:
static std::map m<data *, std::shared_ptr<data> >;

struct container {
    data* ptr;
};

void someFunc(container* receiver /* wants to be filled */) {
    auto myData = createData(); // returns shared_ptr<data>, I can't do anything about it
    receiver->ptr = myData.get();
    m[receiver->ptr] = myData;
}


void someOtherFunc(container* receiver)
{
  // delete receiver->ptr;
  m.erase(receiver->ptr);
}

这通过地图延长了shared_ptr 的寿命。

【讨论】:

  • 完美!这正是我所需要的。谢谢楼主!
  • 我很高兴它可以帮助你:)
  • 实际上我正在将Spine 集成到我的游戏中。它确实有支持主要游戏引擎的运行时,但我使用的是不受官方支持的引擎。对于这些场景,Spine 有一个“通用”运行时,它是在 ANSI C 中,所以你可以让它与任何引擎一起工作。要将其集成到项目中,我必须实现两个函数(提供声明)来创建和销毁纹理。 Spine 传入了一个 struct*,它需要一个纹理指针(因此它可以稍后将它们传回给我进行渲染),但我的引擎给了我以 shared_ptr 形式加载的纹理
【解决方案2】:

std::shared_ptr 不会放弃所有权,因此您必须将其保存在类中的某个位置以确保指针不会被删除。不过,您可以使用获取的shared_ptr 而不是存储原始指针。原始指针几乎总是一个糟糕的选择。

【讨论】:

  • 我无法修改数据源函数或接收器类的源代码。它们来自两个不同的库,我无法访问它们的源代码。所以我需要弄清楚如何让它们一起工作。
【解决方案3】:

这是不可能的。

即使您在 container 析构函数中处理了对象销毁,您也不能保证没有其他对象有 std::shared_ptr 持有指向该对象的指针(在这种情况下您将看到 double free 错误)。

如果对象生命周期由std::shared_ptr 管理(没有特殊删除器),那么您只能通过std::shared_ptrstd::weak_ptr 控制对象生命周期。

【讨论】:

  • 这不是不可能的(参见链接的副本),但这绝对不是微不足道的,也不是一个特别好的主意。
  • @aruisdante 感谢您的评论。是的,从技术上讲,您是正确的,但我提到在答案中没有特殊删除器是不可能的。
【解决方案4】:

我能从中看出的唯一方法(如果你的设计允许的话)是包装你的容器:

struct container {
    data* ptr;
};

struct container_wrapper {
    std::shared_ptr<data> ptr; // ensure this lives as long as needed
    container cnt;
};

void someFunc(container_wrapper& receiver /* wants to be filled */) {
    receiver.ptr = createData();
    receiver.cnt.ptr = receiver.ptr.get();
}

【讨论】:

    猜你喜欢
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多