在不破坏托管对象的情况下删除 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_ptr
和 std::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
的生命。
我处于以下情况:
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_ptr
和 std::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
的生命。