删除 boost::bind 的原始指针参数
假设我已经分配了堆A*
,我想将其作为参数传递给boost::bind
。 boost::bind
被保存在一些 STL 中(例如 boost::functions
的容器)以便以后处理。
我想确保 A*
将在 STL 容器销毁时被销毁。
演示:
A* pA = new A();
// some time later
container.push_back(boost::bind(&SomeClass::HandleA, this, pA);
// some time later
container is destroyed => pA is destroyed too
如何才能做到?
编辑
也许我想要的并不那么现实。
我有原始指针和接收原始指针的函数。调用通过boost::bind的方式进行延迟。此时我想要自动内存管理,以防 boost::bind 想要执行。我很懒,所以我想使用“现成的”智能指针解决方案。
std::auto_ptr 看起来是一个不错的候选者,但是......
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, pAutoA);
无法编译(请参阅此处)
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, boost::ref(pAutoA));
pAutoA 被销毁,删除底层 pA。
编辑02
在提到的容器中,我需要存储具有不同参数的杂项“回调”。其中一些是指向对象的原始指针。由于代码很旧,我并不总是可以更改它。
编写自己的包装器来在容器中存储回调是最后的手段(虽然可能是唯一的手段),因此是赏金。
Lets say I have heap allocated A*
, which I want to pass as argument to boost::bind
.boost::bind
is saved for later processing in some STL like container of boost::functions
's.
I want to ensure A*
will be destroyed at destruction of the STL container.
To demostrate:
A* pA = new A();
// some time later
container.push_back(boost::bind(&SomeClass::HandleA, this, pA);
// some time later
container is destroyed => pA is destroyed too
How can it be done?
EDIT
Maybe what I want is not that realistic.
I have raw pointer and function which receives the raw pointer. The call is delayed by means of boost::bind. At this point I want automatic memory management in case boost::bind want executed. I'm lazy, so I want to use "ready" smart-pointer solution.
std::auto_ptr looks like a good candidate, however ...
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, pAutoA);
doesn't compile (see here)
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, boost::ref(pAutoA));
pAutoA is destroyed, deleting underlying pA.
EDIT 02
In the mentioned container I will need to store misc "callbacks" with different arguments. Some of them are raw pointers to object. Since the code is old, I not always can change it.
Writing own wrapper for storing callbacks in container is last resort (while maybe the only one), hence bounty.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
@pmjordan 的想法已经在朝着正确的方向发展。您回答说您不能使用
shared_ptr
,因为一旦构建您就无法收回其所有权。但这并不完全正确:使用shared_ptr
的自定义删除器机制,您可以。方法如下:为您的
A
和f(A*)
假设这些玩具定义:编写一个可以“关闭”的删除器:
然后您可以编写一个
take()
函数来获取shared_ptr
的所有权> 再次有效负载:(这会将有效负载保留在剩余的
shared_ptr
实例中,但对于您的情况,这是可以的,并且assert()
涵盖了不适用的情况) .现在您可以像这样手动包装
f(A*)
:最后,测试这两个场景:
使用
1
参数执行测试程序将打印且没有(或任何其他参数),它将打印
您可以扩展测试工具以首先将
func
放入容器中,但它仍然是安全的。在这种情况下,唯一不安全的是多次调用func
副本(但随后您将触发take()
中的第二个断言)。编辑:请注意,此机制不是线程安全的。为了使其线程安全,您需要为
opt_delete
提供互斥体,以将operator()
与take()
同步。The idea of @pmjordan was already going in the right direction. You replied that you can't use
shared_ptr
, because you can't take ownership back from it once constructed. But that is not entirely correct: withshared_ptr
's custom deleter mechanism, you can. This is how:Assume these toy defintions for your
A
andf(A*)
:Write a deleter that can be "switched off":
Then you can write a
take()
function that takes ownership of theshared_ptr
payload again:(this will leave the payload in the remaining
shared_ptr
instances, but for your case, that's ok, and theassert()
s cover the cases when it's not).Now you can manually wrap
f(A*)
like this:And finally, test the two scenarios:
Executing the test program with a
1
argument will printand without (or any other argument), it will print
You can extend the test harness to put
func
into a container first, but it'll still be safe. The only thing that isn't safe in the case is calling thefunc
copies more than once (but then you'll trigger the second assertion intake()
).EDIT: Note that this mechanism isn't thread-safe. To make it thread-safe, you need to supply
opt_delete
with a mutex to synchroniseoperator()
withtake()
.我假设你的意思是你有一些函数,我们称之为
f()
,它需要一个A*
,然后你用boost::bind
代理它>?您可以更改此函数以接受 Boost/TR1shared_ptr
吗?使用shared_ptr
(或者不太可能,C++98std::auto_ptr
)应该可以解决您的生命周期问题。或者,如果您无法更改
f
本身,则可以创建一个包装器,它接受shared_ptr
,提取原始指针并调用f< /代码> 与它。如果您发现自己编写了很多这样的包装器,则假设函数签名相似,您也许可以创建一个模板来生成它们。
I assume you mean you have some function, let's call it
f()
which takes anA*
, which you then proxy withboost::bind
? Can you change this function to accept a Boost/TR1shared_ptr<A>
instead? Using ashared_ptr
(or, less likely, a C++98std::auto_ptr
) should solve your lifecycle problem.Alternatively, if you can't change
f
itself, you could create a wrapper which accepts ashared_ptr<A>
, pulls out the raw pointer and callsf
with it. If you find yourself writing a lot of these wrappers, you may be able to create a template for generating them, assuming the function signatures are similar.注意!这太丑了!
刚刚完成了一些概念验证。嗯,据我所知,它按照要求做了 - 但这个东西依赖于 const_cast 假设。如果您决定在程序中使用类似的东西,请准备好仔细检查程序中始终发生的所有复制结构,并使用 valgrind 来验证没有任何泄漏/损坏。
技巧在于定义您自己的包装类,它忽略 const 限定符并允许 auto_ptr 所有权从 const 引用的 auto_ptr 转移。例如,如果您尝试复制向量本身,这可能会变得疯狂。
因此,请务必仔细阅读向量复制语义、auto_ptr 所有权转移语义,最重要的是 - 只需使用 shared_ptr :)
NB! This is UGLY!
Have just scrateched some proof of concept. Well, it does what requested, as far as I can see - but this stuff relies on const_cast assumption. If you decide to use something like that in your program, be ready to double check all copy constructions happening in your program all the time, and using valgrind to verify nothing is leaked/corrupted.
Trick is in defining you own wrapper class, that ignores const qualifiers and allows auto_ptr ownership transfer from const referenced auto_ptr. This can get crazy if you ll try, for example, copy vector itself.
So be sure to read carefuly about vector copy semantics, auto_ptr ownership transfer semantics and, best of all - just use shared_ptr :)
它不需要非常复杂:
它有一个问题,您需要通过 MyContainer & 将它传递给其他函数。而不是 std::vector 引用,否则可以调用原始的push_back,并且它允许您可以在不提供 A* 指针的情况下push_back。此外,它不会检查绑定参数是否与 pA 是相同的 A* 对象。您可以通过更改push_back原型来解决这个问题:
It doesn't need to be very complex:
It has one problem that you need to pass it to other functions via MyContainer & instead of std::vector reference, otherwise the original push_back can be called and it allows for cases where you can push_back without providing the A* pointer. Also it has no check for bind parameters to be the same A* object than pA. You can fix that by changing the push_back prototype: