shared_ptr是Boost库中的引用计数智能指针.
引用计数的问题在于它不能处理循环.我想知道如何用C++解决这个问题.
请不要这样的建议:"不要制作周期",或"使用weak_ptr".
编辑
我不喜欢只使用weak_ptr的建议,因为很明显,如果你知道你会创建一个循环,那么你就不会有问题.如果在运行时生成shared_ptrs,您也无法知道编译时会有一个循环.
所以,请自行删除使用weak_ptr的答案,因为我特别要求不要那些答案......
我正在研究如何std::tr1::shared_ptr<>提供强制转换为bool的能力.在尝试创建一个可以作为简单解决方案进行bool的智能指针时,我已经被抓住了,即
operator bool() {
return m_Ptr!=0;
}
Run Code Online (Sandbox Code Playgroud)
通常最终可以隐式地转换为指针类型(可能是通过类型提升),这通常是不合需要的.boost和Microsoft实现似乎都使用了涉及强制转换的技巧unspecified_bool_type().任何人都可以解释这种机制如何工作以及它如何防止隐式转换为底层指针类型?
为什么我收到以下代码的以下错误?
1>C:\Libs\boost_1_44\boost/smart_ptr/shared_ptr.hpp(259): error C2683: 'dynamic_cast' : 'my_namespace::A' is not a polymorphic type
1> D:\[location]\[header_filename].h(35) : see declaration of 'my_namespace::A'
1> C:\Libs\boost_1_44\boost/smart_ptr/shared_ptr.hpp(522) : see reference to function template instantiation 'boost::shared_ptr<T>::shared_ptr<my_namespace::A>(const boost::shared_ptr<my_namespace::A> &,boost::detail::dynamic_cast_tag)' being compiled
1> with
1> [
1> T=my_namespace::B
1> ]
1> [location]\[source_filename].cpp(217) : see reference to function template instantiation 'boost::shared_ptr<T> boost::dynamic_pointer_cast<my_namespace::B,striker::A>(const boost::shared_ptr<my_namespace::A> &)' being compiled
1> with
1> [
1> T=my_namespace::B
1> ]
1>C:\Libs\boost_1_44\boost/smart_ptr/shared_ptr.hpp(260): fatal error C1903: unable to recover from previous error(s); stopping compilation
Run Code Online (Sandbox Code Playgroud)
C++代码或多或少如下:
#include <list>
#include …Run Code Online (Sandbox Code Playgroud) C++ 11的std :: shared_ptr <>提供了一种bool运算符.
operator unspecified-bool-type() const;
Run Code Online (Sandbox Code Playgroud)
(operator bool() const由于类型的隐式转换带来的危险,这不是直接的bool.)
为什么std :: weak_ptr <>没有类似的运算符?我发现自己经常打字
if( !wp.expired() )
Run Code Online (Sandbox Code Playgroud)
当我想打字的时候
if( wp )
Run Code Online (Sandbox Code Playgroud)
为什么没有针对weak_ptr的bool转换?
我有一个资源管理器,像Andrei Alexandrescu在Modern C++ Design一书中提出的那样,遵循基于策略的设计.我遇到了麻烦,因为我的资源管理器需要能够通过提供对托管资源的引用shared_from_this().
我建立了一个简单的例子来重现我的问题,结果你可以在这里看到.
基本上我有一些需要对其经理的引用的托管资源:
template <typename T>
class managed_resource
{
typedef std::shared_ptr<manager<T>> manager_ptr;
public:
managed_resource(manager_ptr const & parent)
: parent_(parent)
{
}
/* ... */
private:
manager_ptr parent_;
};
Run Code Online (Sandbox Code Playgroud)
以及存储和提供资源的经理:
template <typename Policy>
class manager
: Policy
, std::enable_shared_from_this<manager<Policy>>
{
typedef managed_resource<Policy> resource;
typedef std::shared_ptr<resource> resource_ptr;
public:
resource_ptr get_resource(std::string const & name)
{
Policy & p = *this;
if(p.find(name))
{
return p.get(name);
}
resource_ptr res = std::make_shared<resource>(shared_from_this());
p.store(name, res);
return res;
}
};
Run Code Online (Sandbox Code Playgroud)
如您所见,存储本身是基于策略的.虽然管理者确实创建了资源,但策略可以在存储信息的各种方法之间自由决定(例如,它可以选择不存储任何东西并且每次都创建新资源). …
这个答案引用了N4082,它表明即将进行的更改std::shared_ptr将允许两者T[]和T[N]变体:
不同于
unique_ptr用于阵列部分特,都shared_ptr<T[]>和shared_ptr<T[N]>将是有效的,都将导致delete[]被称为对象的管理的阵列上.Run Code Online (Sandbox Code Playgroud)template<class Y> explicit shared_ptr(Y* p);要求:
Y应为完整类型.表达式delete[] p,当T是数组类型时,或者delete p,当T不是数组类型时,应该是格式良好的,应该具有良好定义的行为,并且不应抛出异常.如果T是U[N],Y(*)[N]应转换为T*; 当T是U[],Y(*)[]应转变成T*; 否则,Y*应可转换为T*.
除非我弄错了,Y(*)[N]否则只能通过获取数组的地址来形成,这显然不能被a拥有或删除shared_ptr.我也没有看到任何N以任何方式强制使用托管对象大小的指示.
允许T[N]语法的动机是什么?它是否产生任何实际效益,如果是,它是如何使用的?
我有使用的成员函数(方法)
std::enable_shared_from_this::weak_from_this()
Run Code Online (Sandbox Code Playgroud)
简而言之:weak_from_this返回weak_ptr到这个。一个警告是它不能从构造函数中使用。如果有人使用继承的类的构造函数中的函数,则该函数weak_from_this将返回expired weak_ptr。我通过断言检查它是否未到期来进行防范,但这是运行时检查。
有没有一种方法可以在编译时进行检查?
为了解决我的应用程序中一个非常特殊的问题,我需要一个指向已分配数据的共享指针,但对于外部世界,底层数据类型应保持隐藏状态.
我可以通过创建我的其他所有类继承的某种Root类来解决这个问题,并在此Root类上使用shared_ptr,如下所示:
std::shared_ptr<Root>
Run Code Online (Sandbox Code Playgroud)
然而:
奇怪的是,似乎你可以在void上创建一个shared_ptr,这似乎工作正常,如下例所示:
class X
{
public:
X() {std::cout << "X::ctor" << std::endl;}
virtual ~X() {std::cout << "X::dtor" << std::endl;}
};
typedef std::shared_ptr<void> SharedVoidPointer;
int main()
{
X *x = new X();
SharedVoidPointer sp1(x);
}
Run Code Online (Sandbox Code Playgroud)
x被正确删除,在一个更大的实验中,我可以验证共享指针确实完成了它需要做的事情(删除x,最后一个shared_ptr结束了灯光).
当然,这解决了我的问题,因为我现在可以使用SharedVoidPointer数据成员返回数据,并确保它正确地清理它应该在哪里.
但这是否可以保证在所有情况下都有效?它显然适用于Visual Studio 2010,但这是否也可以在其他编译器上正常工作?在其他平台上?
我经常在代码中看到这种模式,绑定shared_from_this为成员函数的第一个参数,并使用async_*函数调度结果.以下是另一个问题的示例:
void Connection::Receive()
{
boost::asio::async_read(socket_,boost::asio::buffer(this->read_buffer_),
boost::bind(&Connection::handle_Receive,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
Run Code Online (Sandbox Code Playgroud)
使用shared_from_this()而不是使用的唯一原因this是在调用成员函数之前保持对象存活.但除非在某处有某种类型的增强魔法,因为this指针是类型的Connection*,所有都handle_Receive可以,并且返回的智能指针应该立即转换为常规指针.如果发生这种情况,那么没有任何东西可以让对象保持活力.当然,在呼叫中没有指针shared_from_this.
但是,我经常看到这种模式,我不敢相信它在我看来完全被打破了.当操作完成时,是否有一些Boost魔法会导致shared_ptr转换为常规指针?如果是这样,这是在某处记录的吗?
特别是,在某个地方记录共享指针将保持存在直到操作完成?调用get_pointer强指针然后在返回的指针上调用成员函数是不够的,除非强指针在成员函数返回之前不被销毁.
说我有一个shared_ptr带有自定义分配器和自定义删除器的。
我在标准中找不到任何内容讨论删除器的存储位置:它没有说自定义分配器将用于删除器的内存,也没有说不会。
这是未指定的还是我只是缺少了什么?
c++ ×10
shared-ptr ×10
c++11 ×3
c++17 ×3
stl ×2
weak-ptr ×2
allocator ×1
boost ×1
boost-asio ×1
constructor ×1
dynamic-cast ×1
templates ×1
visual-c++ ×1