C ++ 17和静态临时生存期的参考扩展

时间:2018-09-26 03:56:51

标签: c++ visual-studio-2017 polymorphism c++17 temporary-objects

我有一些代码正在尝试做一种单例多态,例如:

// 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;

这是代码中的编译器错误还是违反标准?

1 个答案:

答案 0 :(得分:1)

由于评论中的结论似乎是这确实是编译器错误,因此我reported an issue

这个问题待一会儿再解决。