我有一些代码正在尝试做一种单例多态,例如:
// header
struct B
{
virtual ~B() = default;
virtual void F() = 0;
static const B& Type1;
static const B& Type2;
};
// cpp
struct D1 : B
{
void F() override;
};
struct D2 : B
{
void F() override;
};
const B& B::Type1 = D1();
const B& B::Type2 = D2();
// consumer
class Usage
{
public:
Usage() : m_b(&B::Type1) {}
void UseType1() { m_b = &B::Type1; }
void UseType2() { m_b = &B::Type2; }
void F() const { m_b->F(); }
private:
const B* m_b;
};
因此,消费类始终使用这些实例之一,但是具体的实例是在运行时确定的。 (它在顶层使用了多态性的引用,而不是使用指针,以便正确删除对象,但也避免像智能指针那样将它们放在堆上。)
据我了解,对临时文件的const引用应该在引用的生存期内延长该临时文件的生存期(一些关于生存期的警告通常在函数出口处终止或类似的功能)。由于这些特定的引用具有静态作用域,因此它们在过程的整个生命周期中都应存在,因此也应在此范围内保持短暂的时间。
此代码可以在VS2015中正常工作,在默认C ++ 14编译模式下也可以在VS2017 15.8.5中工作。
但是,如果我将VS2017切换为C ++ 17编译模式,那么(在没有任何编译器警告的情况下)这会在运行时崩溃,因为某些特定的const B*
指向具有完全不相关的vtable的对象-即。应该在其中一个实例上保留一些内存的东西。我认为这意味着临时物被过早销毁。
通过避免使用临时属性,我可以使其表现出预期的效果:
static const D1 GlobalType1;
static const D2 GlobalType2;
const B& B::Type1 = GlobalType1;
const B& B::Type2 = GlobalType2;
这是代码中的编译器错误还是违反标准?