【发布时间】:2016-10-08 00:24:09
【问题描述】:
如果你有一个带有虚拟方法的类 Base 和一个实现虚拟方法的类 Implementation,有没有办法将 std::shared_ptr & 转换为 std::shared &?对于 const 引用,编译器允许这样做,但对于非 const 引用,它会像下面代码中的“案例 A”一样失败。有没有简单的方法可以做到这一点?
如果不是,我在案例 B 中的解决方法“questionable_cast”的安全性如何?
#include <iostream>
#include <memory>
class Base
{
public:
virtual void set_value(int x) = 0;
};
class Implementation : public Base
{
public:
Implementation() : m_value(0) { }
void set_value(int x) override
{
m_value = x;
}
int get_value() const
{
return m_value;
}
private:
int m_value;
};
void do_something(std::shared_ptr<Base>& base)
{
base->set_value(5);
/// Code like this makes the non-const argument necessary
base = std::make_shared<Implementation>();
}
template <class T, class U>
std::shared_ptr<T>& questionable_cast(std::shared_ptr<U>& u)
{
/// This code is here to assure the cast is allowed
std::shared_ptr<T> tmp = u;
(void)tmp;
return *reinterpret_cast<std::shared_ptr<T>*>(&u);
}
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
// The following line causes a compiler error:
// invalid initialization of reference of type ‘std::shared_ptr<Base>&’ ...
// do_something(a);
// do_something(std::dynamic_pointer_cast<Base>(a));
// This is the workaround
do_something(questionable_cast<Base>(a));
std::cerr << "a = " << a->get_value() << std::endl;
return 0;
}
【问题讨论】:
-
额外问题:为什么这被否决了?
-
您为什么要尝试使用参考来执行此操作,而不是像在
questionable_cast函数中那样制作副本?使用引用不会增加计数器,并使引用无效。 -
我没有投反对票,但可能的原因是:为什么你想这样做?像这样使用 reinterpret_cast 必然会违反严格的别名规则,从而导致未定义的行为。
-
我更新了代码,以便您可以看到为什么参数需要是非常量引用。相信我,我不想使用 reinterpret_cast。这就是为什么我要问是否有办法解决它
-
为什么
Derived*&(或Derived**)不能转换为Base*&(或Base**)肯定有几个答案,这是同一个问题。简而言之:它不是类型安全的。 (考虑将指向不同派生类的指针传递给do_something的情况。)
标签: c++ c++11 casting shared-ptr