在不破坏托管对象的情况下删除 std::shared_ptr?

Delete std::shared_ptr without destroying the managed object?

我处于以下情况:

struct container {
    data* ptr;
};

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

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

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

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

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

这可能吗?

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

这不可能。

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

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

控制对象生命周期

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

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();
}
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的生命。