And*_*ost 5 c++ casting shared-ptr
我有一个使用boost::shared_ptrs 的程序,特别是依赖于use_count执行优化的准确性.
例如,想象一个带有两个参数指针的加法运算,称为lhs和rhs.说他们都有类型shared_ptr<Node>.当需要执行添加时,我将检查use_count,如果我发现其中一个参数的引用计数恰好为1,那么我将重用它来执行操作.如果两个参数都不能重用,我必须分配一个新的数据缓冲区并执行不合适的操作.我正在处理庞大的数据结构,因此就地优化非常有用.
因此,我无法shared_ptr无理由地复制s,即每个函数都shared_ptr通过引用或const引用来获取s以避免失真use_count.
我的问题是这样的:我有时会有一个shared_ptr<T> &我想投的东西shared_ptr<T const> &,但是如何在不扭曲使用次数的情况下做到这一点? static_pointer_cast返回一个新对象而不是引用.我倾向于认为只投下整个就行了shared_ptr,如:
void f(shared_ptr<T> & x)
{
shared_ptr<T const> & x_ = *reinterpret_cast<shared_ptr<T const> *>(&x);
}
Run Code Online (Sandbox Code Playgroud)
我非常怀疑这符合标准,但正如我所说,它可能会奏效.有没有办法做到这一点,保证安全和正确?
更新以集中问题
批评设计无助于回答这篇文章.有两个有趣的问题需要考虑:
是否有任何保证(由作者boost::shared_ptr或标准,在案例中std::tr1::shared_ptr)shared_ptr<T>并且shared_ptr<T const>具有相同的布局和行为?
如果(1)为真,那么上面是reinterpret_cast的合法使用吗?我认为你很难找到一个为上面的例子生成失败代码的编译器,但这并不意味着它是合法的.无论您的答案是什么,您能否在C++标准中找到对它的支持?
Nic*_*las 11
我有时会有一个
shared_ptr<T> &我想投的东西shared_ptr<T const> &,但是如何在不扭曲使用次数的情况下做到这一点?
你没有.这个概念是错误的.考虑用裸指针发生了什么T*和const T*.当你把你T*变成a时const T*,你现在有两个指针.您没有对同一指针的两个引用; 你有两个指针.
为什么智能指针会有所不同?你有两个指针:一个到一个T,一个到一个const T.他们都共享同一个对象的所有权,所以你使用其中两个.use_count因此你应该是2而不是1.
你的问题是你试图use_count超越其含义,为其他目的选择其功能.简而言之:你做错了.
你的你做什么说明shared_ptr小号谁的use_count是一个是... 可怕.你基本上是说,某些功能增选它的参数,它调用者一个明确使用(因为调用者显然仍在使用它).并且调用者不知道声明了哪一个(如果有的话),因此调用者不知道在函数之后参数的状态是什么.修改这样的操作的参数通常不是一个好主意.
另外,你所做的只有在你通过shared_ptr<T>引用传递时才能工作,这本身并不是一个好主意(比如常规指针,智能指针应该几乎总是按值来获取).
简而言之,你正在使用一个非常常用的具有明确定义的习语和语义的对象,然后要求它以几乎从不使用的方式使用,其专用语义与每个人实际使用它们的方式相反.这不是一件好事.
你已经有效地创建了co-optable指针的概念,这是一个共享指针,可以处于3种使用状态:空,仅供给你的人使用,因此你可以从中偷取,并且使用超过一个人,所以你不能拥有它.这不是shared_ptr支持的语义.因此,您应该编写自己的智能指针,以更自然的方式提供这些语义.
能够识别你所拥有的指针实例数和你拥有的实际用户数之间差异的东西.这样,您可以正确地传递它的值,但是你有一些方法可以说你正在使用它并且不希望其中一个其他函数声明它.它可以在shared_ptr内部使用,但它应该提供自己的语义.
static_pointer_cast是适合您已经确定的工作 \xe2\x80\x94 的工具。
它的问题不在于它返回一个新对象,而在于它使旧对象保持不变。您想要摆脱非常量指针并继续使用常量指针。你真正想要的是static_pointer_cast< T const >( std::move( old_ptr ) )。但右值引用没有重载。
解决方法很简单:手动使旧指针失效std::move。
auto my_const_pointer = static_pointer_cast< T const >( modifiable_pointer );\nmodifiable_pointer = nullptr;\nRun Code Online (Sandbox Code Playgroud)\n\n它可能会比 稍慢reinterpret_cast,但它更有可能工作。不要低估库实现的复杂性,以及滥用时可能会失败的程度。
旁白:使用pointer.unique()而不是use_count() == 1. 某些实现可能使用没有缓存使用计数的链表,从而实现use_count()O(N),而unique测试仍为 O(1)。该标准建议unique进行写时复制优化。
编辑:现在我看到你提到
\n\n\n\n\n我永远不能
\nshared_ptr无缘无故地复制 s ,即每个函数都shared_ptr通过引用或 const 引用获取 s 以避免扭曲use_count。
这是做错了。您在已有的基础上添加了另一层所有权语义shared_ptr。它们应该按值传递,并std::move在调用者不再需要所有权的情况下使用。如果探查器说您正在花时间调整引用计数,那么您可以在内循环中添加一些对指针的引用。但作为一般规则,如果您无法设置指向的指针,nullptr因为您不再使用它,但其他人可能会使用它,那么您就真的失去了所有权。
如果将 a 转换shared_ptr为不同的类型,而不更改引用计数,这意味着您现在将有两个指向相同数据的指针。因此,除非您擦除旧指针,否则您无法shared_ptr在不“扭曲引用计数”的情况下使用 s 执行此操作。
我建议您在这里使用原始指针,而不是特意不使用shared_ptrs 的功能。如果有时需要创建新的引用,请使用enable_shared_from_this派生新的shared_ptr现有原始指针。