根据这本书:The C++ Standard Library: a tutorial and reference
我引用以下内容:
转换运算符允许转换指向不同类型的指针。语义与相应的运算符相同,结果是另一个不同类型的共享指针。请注意,使用普通的强制转换操作符是不可能的,因为它会导致未定义的行为
因此,例如,以下代码会产生未定义的行为:
shared_ptr<Base> base_ptr (new Derived);
shared_ptr<Derived>(static_cast<Derived*>(base_ptr.get())); --> Undefined Behaviour.
因此,应使用static_pointer_cast()
代替。
第二个例子:
shared_ptr<void> sp(new int); // shared pointer holds a void* internally
shared_ptr<int>(static_cast<int*>(sp.get())) // ERROR: undefined behavior
标准确实支持这样的声明吗?
答案 0 :(得分:3)
假设:
shared_ptr<Base> base_ptr (new Derived); // ** see below
shared_ptr<Derived> derived_ptr;
表达式:
Derived* p = static_cast<Derived *>(base_ptr.get());
从基类指针正确地产生指向派生类接口的指针。但是,这是一个原始指针。
这本身不是UB。
然而,下一个逻辑错误可能是:
derived_ptr.reset(p);
这会产生一个微妙而令人讨厌的错误,因为你现在有两个不同的shared_ptr
,每个都有自己的控制块(通过它来跟踪受控对象的生命周期) )。
derived_ptr
和base_ptr
现在将p
独立控制对象指针的生命周期。
相比之下,
derived_ptr = std::static_pointer_cast<Derived>(base_ptr);
导致derived_ptr
与base_ptr
共享同一个控制块,因此,新对象的生命周期将得到正确管理。
请注意,在所述示例中,您无论如何都有UB。
如果static_cast
确实指向Derived
,则您只能base_ptr
到Derived
。在你的情况下,它不是。它指向Base
并且没有任何数量的投射会正确地向下投射。
我已在上面进行了编辑以纠正此问题。
答案 1 :(得分:1)
不要在共享指针上使用static_cast
。这是错误的,因为您还必须传输删除器信息。使用std::static_pointer_cast
:
std::shared_ptr<int> int_ptr = std::static_pointer_cast<int>(sp);
您正在做的事情将使用新的引用计数器创建一个新的shared_ptr
对象。当两个shared_ptr
对象超出范围时,两者都将尝试删除相同的指针,这将导致段错误。
答案 2 :(得分:1)
共享指针是两件事;指向数据的指针和指向控制块的指针。
当您将指向数据的指针显式转换为共享ptr时,会导致它分配新的控制块。
如果同一个poimter由2个控制块控制,则两个删除器在超出范围时将被调用。默认删除器删除指针,并执行两次是未定义的行为。
但是,立即。。
。这里我们有一种不使用静态指针的替代方法:
shared_ptr<void> sp(new int); // shared pointer holds a void* internally
shared_ptr<int>(sp, static_cast<int*>(sp.get())) //OK: aliasing constructor
&#34;别名&#34; shared_ptr
的构造函数允许您传递单独的控制块和数据指针。控制块由任何类型的另一个共享ptr(从中添加引用并获取控制块)表示。