std::static_pointer_cast是否有额外的运行时开销?

6

与 static_cast 相比,也就是说。因此,如果我们有这两个转换

Base* b(new Derived());
Derived* d = static_cast<Derived*>(b); // (1)

shared_ptr<Base> b(new Derived());
shared_ptr<Derived> d = static_pointer_cast<Derived>(b); // (2)

线路(2)比线路(1)慢吗?

1
这只是 static_cast<Derived*>(b.get()) 的语法糖。 - Rapptz
@Rapptz:static_pointer_cast 可以用于 shared_ptr 智能指针对象。 - Cheers and hth. - Alf
1
@Rapptz 这不完全正确,因为 static_pointer_cast 返回的指针与原始指针共享所有权。 - Benno
请纠正我,但n3797说:“看似等效的表达式shared_ptr<T>(static_cast<T*>(r.get()))最终会导致未定义的行为,试图两次删除同一对象。” - user1508519
@remyabel,你是正确的,这就是为什么这两个表达式只是表面上等价的原因。 - Benno
2个回答

9

是的,使用shared_ptr会增加一些开销,因为它需要返回一个新的shared_ptr而不是一个新的裸指针。

boost库中的实现如下:

template<class T, class U> shared_ptr<T> static_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
    (void) static_cast< T* >( static_cast< U* >( 0 ) );

    typedef typename shared_ptr<T>::element_type E;

    E * p = static_cast< E* >( r.get() );
    return shared_ptr<T>( r, p );
}

因此,返回行创建一个shared_ptr,它拥有与您要转换的shared_ptr完全相同的原始指针。看看这个构造函数,它将导致被管理的指针和控制块指针的分配 - 这是额外的开销。基本上是两个指针赋值而不是一个。
编辑2:还会有原子引用计数增量,其性能影响将超过正常增量。
编辑:通常情况下,存在性能问题的警告。实现可能有所不同。这不是标准规定的开销。并且一定一定要测量性能!

你忘记了增加引用计数的成本(原子操作比普通操作要昂贵得多),因为强制转换实际上复制了 shared_ptr。我知道规范没有提到引用计数器,但几乎所有的实现都使用它们,并且它们必须是原子的(线程安全的)。 - John5342
1
@John5342 我一开始也是这么想的,后来改变了主意并将其从我的答案中删除,但现在我又同意你的看法了 :) 当我改变主意时,我误读了规范。 - user2428400
请问 (void) static_cast< T* >( static_cast< U* >( 0 ) ); 在 Boost 实现中的目的是什么(我猜它与类型检查有关,但不确定具体细节)? - Hongxu Chen

1

shared_ptr 会保存所需的信息以及一个删除器函数,以用于关联对象的销毁。共同控制块也会保存在其中,这个块会被相同引用对象的 shared_ptr 实例共享。而 static_pointer_cast 只是简单地将一个指向 shared_ptr 实例的指针进行类型转换,因此,尽管它可以更改指针值,但不应该涉及任何额外开销(除了像复制一个实例一样创建 shared_ptr 实例)。

据我所知,目前没有正式的保证(如果这对您很重要,请查阅相关信息)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接