C++17 和静态临时生命周期的引用扩展
C++17 and reference extension of static temporary lifetime
我有一些代码试图做一种单例多态性,像这样:
// 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;
};
因此消费 class 总是使用这些实例之一,但具体的实例是在运行时决定的。 (它在顶层使用多态引用而不是指针,以便正确删除对象,但也避免像智能指针那样将它们放在堆上。)
据我了解,对临时对象的 const 引用应该会在引用的生命周期内延长该临时对象的生命周期(关于生命周期的一些注意事项通常在函数退出或类似的情况下结束)。由于这些特定的引用具有静态范围,因此它们应该在进程的生命周期内存在,因此也将临时文件保持那么久。
此代码在 VS2015 中按预期工作,在默认 C++14 编译模式下也在 VS2017 15.8.5 中工作。
但是,如果我将 VS2017 切换到 C++17 编译模式,那么(没有任何编译器警告)这会在运行时崩溃,因为某些特定的 const B*
指向一个具有完全不相关的 vtable 的对象 - - IE。某些东西踩到了本应为其中一个实例保留的内存。我认为这意味着临时文件被销毁得太早了。
我可以通过避免使用临时文件来使它按预期运行:
static const D1 GlobalType1;
static const D2 GlobalType2;
const B& B::Type1 = GlobalType1;
const B& B::Type2 = GlobalType2;
这是编译器错误还是代码中的标准违规?
由于评论中的结论似乎是这确实是一个编译器错误,所以我reported an issue。
将问题再悬而未决一段时间,直到得出结论。
我有一些代码试图做一种单例多态性,像这样:
// 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;
};
因此消费 class 总是使用这些实例之一,但具体的实例是在运行时决定的。 (它在顶层使用多态引用而不是指针,以便正确删除对象,但也避免像智能指针那样将它们放在堆上。)
据我了解,对临时对象的 const 引用应该会在引用的生命周期内延长该临时对象的生命周期(关于生命周期的一些注意事项通常在函数退出或类似的情况下结束)。由于这些特定的引用具有静态范围,因此它们应该在进程的生命周期内存在,因此也将临时文件保持那么久。
此代码在 VS2015 中按预期工作,在默认 C++14 编译模式下也在 VS2017 15.8.5 中工作。
但是,如果我将 VS2017 切换到 C++17 编译模式,那么(没有任何编译器警告)这会在运行时崩溃,因为某些特定的 const B*
指向一个具有完全不相关的 vtable 的对象 - - IE。某些东西踩到了本应为其中一个实例保留的内存。我认为这意味着临时文件被销毁得太早了。
我可以通过避免使用临时文件来使它按预期运行:
static const D1 GlobalType1;
static const D2 GlobalType2;
const B& B::Type1 = GlobalType1;
const B& B::Type2 = GlobalType2;
这是编译器错误还是代码中的标准违规?
由于评论中的结论似乎是这确实是一个编译器错误,所以我reported an issue。
将问题再悬而未决一段时间,直到得出结论。