boost :: shared_ptr可以释放存储的指针而不删除吗?
我可以看到文档中没有发布功能,也在FAQ中解释了为什么它不提供发布功能,类似于发布不能在不唯一的指针上完成。我的指针是独一无二的。我该如何发布我的指针? 或者哪个提升智能指针类使用,这将允许我释放指针? 我希望你不要说使用auto_ptr:)
答案 0 :(得分:28)
别。 Boost的FAQ条目:
问即可。为什么shared_ptr不提供release()函数?
<强> A 即可。 shared_ptr 不能放弃所有权,除非它是唯一的(),因为另一个副本仍会销毁该对象。
考虑:
shared_ptr<int> a(new int); shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2 int * p = a.release(); // Who owns p now? b will still call delete on it in its destructor.
此外,release()返回的指针很难可靠地解除分配,因为源shared_ptr可能是使用自定义删除器创建的。
因此,如果它是指向您对象的唯一shared_ptr实例(当unique()返回true时)并且该对象不需要特殊的删除器,那么这将是安全的。如果您使用了这样的.release()函数,我仍然会质疑您的设计。
答案 1 :(得分:21)
你可以使用假删除器。那么指针实际上不会被删除。
struct NullDeleter {template<typename T> void operator()(T*) {} };
// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );
答案 2 :(得分:7)
孩子们,不要在家里这样做:
// set smarty to point to nothing
// returns old(smarty.get())
// caller is responsible for the returned pointer (careful)
template <typename T>
T* release (shared_ptr<T>& smarty) {
// sanity check:
assert (smarty.unique());
// only one owner (please don't play games with weak_ptr in another thread)
// would want to check the total count (shared+weak) here
// save the pointer:
T *raw = &*smarty;
// at this point smarty owns raw, can't return it
try {
// an exception here would be quite unpleasant
// now smash smarty:
new (&smarty) shared_ptr<T> ();
// REALLY: don't do it!
// the behaviour is not defined!
// in practice: at least a memory leak!
} catch (...) {
// there is no shared_ptr<T> in smarty zombie now
// can't fix it at this point:
// the only fix would be to retry, and it would probably throw again
// sorry, can't do anything
abort ();
}
// smarty is a fresh shared_ptr<T> that doesn't own raw
// at this point, nobody owns raw, can return it
return raw;
}
现在,有没有办法检查参考计数的所有者总数是否> 1?
答案 3 :(得分:6)
您需要使用可以请求不删除基础指针的删除程序。
See this answer(已被标记为此问题的副本)以获取更多信息。
答案 4 :(得分:4)
要让指针再次指向任何内容,您可以调用shared_ptr::reset()
。
但是,当您的指针是对象的最后一个引用时,这将删除指向的对象。然而,这首先是智能指针的理想行为。
如果您只想要一个不能保持对象存活的引用,则可以创建boost::weak_ptr
(请参阅boost documentation)。 weak_ptr
保存对对象的引用但不添加引用计数,因此当仅存在弱引用时,对象将被删除。
答案 5 :(得分:3)
分享的基础是信任。如果程序中的某个实例需要释放原始指针,那么几乎可以肯定shared_ptr
是错误的类型。
但是,最近我也想这样做,因为我需要从不同的进程堆中释放。最后,我被告知我使用某些std::shared_ptr
的旧决定没有经过深思熟虑。
我只是经常使用这种类型进行清理。但指针只是在几个地方重复。实际上我需要一个std::unique_ptr
,其中(惊讶)具有release
功能。
答案 6 :(得分:2)
原谅他们,因为他们不知道他们做了什么。 这个例子适用于boost :: shared_ptr和msvs std :: shared_ptr而没有内存泄漏!
template <template <typename> class TSharedPtr, typename Type>
Type * release_shared(TSharedPtr<Type> & ptr)
{
//! this struct mimics the data of std:shared_ptr ( or boost::shared_ptr )
struct SharedVoidPtr
{
struct RefCounter
{
long _Uses;
long _Weaks;
};
void * ptr;
RefCounter * refC;
SharedVoidPtr()
{
ptr = refC = nullptr;
}
~SharedVoidPtr()
{
delete refC;
}
};
assert( ptr.unique() );
Type * t = ptr.get();
SharedVoidPtr sp; // create dummy shared_ptr
TSharedPtr<Type> * spPtr = (TSharedPtr<Type>*)( &sp );
spPtr->swap(ptr); // swap the contents
ptr.reset();
// now the xxx::shared_ptr is empy and
// SharedVoidPtr releases the raw poiter but deletes the underlying counter data
return t;
}
答案 7 :(得分:1)
你可以删除共享指针,这对我来说似乎很相似。如果指针始终是唯一的,那么std::auto_ptr<>
是一个不错的选择。请记住,在STL容器中不能使用唯一指针,因为对它们的操作会进行大量复制和临时复制。
答案 8 :(得分:1)
我不完全确定你的问题是关于实现这个问题,但是如果你想要databus
的行为,那么,如果你从一个shared_ptr
释放值,那么所有其他的共享指针将相同的值变为nullptr,然后您可以在shared_ptr
中放置unique_ptr
来实现该行为。
shared_ptr
输出:
void print(std::string name, std::shared_ptr<std::unique_ptr<int>>& ptr)
{
if(ptr == nullptr || *ptr == nullptr)
{
std::cout << name << " points to nullptr" << std::endl;
}
else
{
std::cout << name << " points to value " << *(*ptr) << std::endl;
}
}
int main()
{
std::shared_ptr<std::unique_ptr<int>> original;
original = std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(50));
std::shared_ptr<std::unique_ptr<int>> shared_original = original;
std::shared_ptr<std::unique_ptr<int>> thief = nullptr;
print(std::string("original"), original);
print(std::string("shared_original"), shared_original);
print(std::string("thief"), thief);
thief = std::make_shared<std::unique_ptr<int>>(original->release());
print(std::string("original"), original);
print(std::string("shared_original"), shared_original);
print(std::string("thief"), thief);
return 0;
}
此行为允许您共享资源(如数组),然后重用该资源,同时使对此资源的所有共享引用无效。
答案 9 :(得分:0)
这是一个可行的黑客攻击。我不推荐它,除非你是真正的约束。
template<typename T>
T * release_shared(std::shared_ptr<T> & shared)
{
static std::vector<std::shared_ptr<T> > graveyard;
graveyard.push_back(shared);
shared.reset();
return graveyard.back().get();
}
答案 10 :(得分:0)
如果您的指针确实是唯一的,请使用std::unique_ptr
或boost::scoped_ptr
如果前者不适用于您的编译器。否则,请考虑将boost::shared_ptr
与boost::weak_ptr
结合使用。有关详细信息,请查看Boost documentation。
答案 11 :(得分:0)
我正在使用Poco :: HTTPRequestHandlerFactory,它希望返回原始HTTPRequestHandler *,Poco框架会在请求完成后删除处理程序。
同样使用DI Sauce项目来创建控制器,但是Injector返回我无法直接返回的shared_ptr,并且返回handler.get()也不好,因为只要此函数返回shared_ptr超出范围并且在执行之前删除然后处理程序,所以这是一个合理的(我认为)理由有一个.release()方法。我最终创建了一个HTTPRequestHandlerWrapper类,如下所示: -
class HTTPRequestHandlerWrapper : public HTTPRequestHandler {
private:
sauce::shared_ptr<HTTPRequestHandler> _handler;
public:
HTTPRequestHandlerWrapper(sauce::shared_ptr<HTTPRequestHandler> handler) {
_handler = handler;
}
virtual void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) {
return _handler->handleRequest(request, response);
}
};
然后工厂
HTTPRequestHandler* HttpHandlerFactory::createRequestHandler(const HTTPServerRequest& request) {
URI uri = URI(request.getURI());
auto path = uri.getPath();
auto method = request.getMethod();
sauce::shared_ptr<HTTPRequestHandler> handler = _injector->get<HTTPRequestHandler>(method + ":" + path);
return new HTTPRequestHandlerWrapper(handler);
}
对Sauce和Poco都很满意并且效果很好。
答案 12 :(得分:0)
我需要通过异步处理程序传递一个指针,并在发生故障时保持自毁行为,但最终的API需要一个原始指针,所以我让这个函数从一个shared_ptr中释放:
#include <memory>
template<typename T>
T * release(std::shared_ptr<T> & ptr)
{
struct { void operator()(T *) {} } NoDelete;
T * t = nullptr;
if (ptr.use_count() == 1)
{
t = ptr.get();
ptr.template reset<T>(nullptr, NoDelete);
}
return t;
}
如果ptr.use_count() != 1
,您将获得nullptr
。
答案 13 :(得分:-1)
简单的解决方案,增加引用,然后泄漏shared_pointer。
boost::shared_ptr<MyType> shared_pointer_to_instance(new MyType());
new boost::shared_ptr<MyType>();
MyType * raw_pointer = shared_pointer_to_instance.get()
这显然会导致shared_ptr和MyType *
的内存泄漏