reshared_cast对shared_ptr的引用

时间:2019-10-04 13:42:05

标签: c++ shared-ptr reinterpret-cast

让B源自A类。通过阅读各种文章,我给人一种像这样的印象

    const std::shared_ptr<const A> a(new B());
    const std::shared_ptr<const B>& b = reinterpret_cast<const std::shared_ptr<const B>&>(a);
出于某些原因,不鼓励使用

,而应该使用reinterpret_pointer_cast。但是,出于性能原因,我想避免创建新的shared_ptr。上面的代码合法吗?是否会导致不确定的行为?它似乎可以在gcc和Visual Studio中使用。

4 个答案:

答案 0 :(得分:1)

您想要static_pointer_cast

const std::shared_ptr<const A> a(new B());
const std::shared_ptr<const B> b = std::static_pointer_cast<const B>(a);

我非常怀疑上述内容是否会导致性能问题。但是,如果您有证据表明shared_ptr会导致性能问题,请回退到原始指针:

    const B* pB = static_cast<const B*>(a.get());

另一个提示。请尝试避免在具有继承关系的类之间使用reinterpret_cast。在存在虚拟方法和/或多重继承的情况下,static_cast将正确地将指针偏移调整为正确的vtable或基本偏移。但是reinterpret_cast不会。 (或者从技术上说:未定义的行为

答案 1 :(得分:0)

reinterpret_cast通常会导致UB。有时出于性能考虑,您愿意冒险使用它,但是您将尽力避免这种情况。在这种情况下,最好使用static_pointer_cast

请注意,即使在这种情况下,即使您不知道可以使用其他演员表,并且愿意冒险使用reinterpret_cast,也必须在演员表转换前后使用一些验证-否则您将得到很多错误,并花费大量时间。

答案 2 :(得分:0)

首先,创建类型为a的对象const std::shared_ptr<const A> a,并使用指向某个类型B的指针对其进行初始化。仅当您可以将B*分配给A*时,此方法才有效,因此应该存在诸如继承之类的关系。忽略这一点,您可以使用reinterpret_cast将某种类型的对象转换为对另一种类型的引用:

  

可以将类型T1的glvalue表达式强制转换为“对...的引用   T2”(如果可以明确表示“指向T1的指针”类型的表达式)   使用reinterpret_cast转换为“ T2的指针”类型   结果指向与源glvalue相同的对象,但是带有   指定的类型。 [注意:也就是说,对于左值,参考类型转换   reinterpret_cast(x)与转换具有相同的效果   带有内置&和*运算符的* reinterpret_cast(&x)(对于reinterpret_cast(x)同样)。 —尾注]

对于指针,reinterpret_cast归结为转换为void*,然后转换为目标类型:

  

对象指针可以显式转换为的对象指针   72当对象指针类型的prvalue v为   转换为对象指针类型“ pointer to cv T”,结果是   static_cast<cv T*>(static_cast<cv void*>(v))

两个静态强制类型转换的语义定义为:

  

“指针指向cv1无效”类型的prvalue可以转换为prvalue   类型为“指向cv2 T的指针”,其中T是对象类型,而cv2是   与cv1相同或更高的cv资格。的   空指针值将转换为   目标类型。如果原始指针值代表地址   内存中一个字节的A和A满足T的对齐要求,   然后结果指针值表示与   原始指针值,即A。任何其他类似结果   指针转换未指定。

我正在工作的平台具有16或32位的近和远指针。在这种情况下,类型shared_ptr<A>shared_ptr<B>具有不同的大小和对齐方式,因此将一种类型转换为另一种类型是不确定的行为。如果对齐方式匹配,则定义静态转换的结果。

但是,关于reinterpret_cast到引用的第一条款也包含一个注释

[ Note: That is, for lvalues, a reference
cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with
the built-in & and * operators (and similarly for reinterpret_cast<T&&>(x)). —end note ]

因此,基本上,强制转换在语义上与具有立即取消引用的指针转换相同。即使指针具有相同的大小(并且兼容的对齐方式),使用强制转换的指针也会违反严格的别名规则,因为取消引用是一种访问。

  

如果程序尝试访问对象的存储值   透过其中之一以外的视线       以下类型的行为未定义:53       —对象的动态类型,       —对象的动态类型的cv限定版本,       —与对象的动态类型类似的类型(定义见4.4),       —一种类型,它是与对象的动态类型相对应的有符号或无符号类型,       —是与动态类型的CV限定版本相对应的有符号或无符号类型的类型       对象的       —集合或联合类型,在其元素中包括上述类型之一或非静态       数据成员(包括递归地包括子聚合的元素或非静态数据成员)       或包含工会)

答案 3 :(得分:0)

仅在调用传递给函数的类型的类的函数(包括成员函数)(包括隐式{时)时,定义shared_ptr或任何其他标准类或模板的功能{1}}参数):

标准中没有任何内容定义了对于任意两个标准类型this和调用Foo并传递Bar的标准函数时发生的情况Foo(甚至适用于用户类型)。

这是定义的;是 un 定义的。不满足最基本的先决条件:使用正确类型的参数。