У меня есть некоторый код, который пытается выполнить своего рода одноэлементный полиморфизм, например так:
// 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;
};
Таким образом, класс потребления всегда использует один из этих экземпляров, но конкретный определяется во время выполнения.(Он использует ссылки для полиморфизма на верхнем уровне, а не указатели, чтобы правильно удалять объекты, но также избегать помещения их в кучу, как это делал бы умный указатель.)
Как я понимаю, константная ссылкаПредполагается, что до временного интервала предполагается продлить время существования этого временного объекта на время существования ссылки (с некоторыми оговорками о времени жизни, обычно заканчивающимися на выходе из функции или чем-то в этом роде).Поскольку эти конкретные ссылки имеют статическую область видимости, они должны существовать на протяжении всего жизненного цикла процесса и, следовательно, также сохранять временные значения в течение этого времени.
Этот код работает, как ожидается, в VS2015, а также в VS2017 15.8.5 встандартный режим компиляции C ++ 14.
Однако, если я переключаю VS2017 в режим компиляции C ++ 17, то (без каких-либо предупреждений компилятора) происходит сбой во время выполнения, потому что какой-то конкретный const B*
указывает наобъект, который имеет совершенно не связанный vtable - т.е.что-то растоптало память, которая должна была быть зарезервирована для одного из экземпляров.Я предполагаю, что это означает, что временное хранилище было уничтожено слишком рано.
Я могу сделать так, чтобы он вел себя так, как ожидалось, избегая использования временного:
static const D1 GlobalType1;
static const D2 GlobalType2;
const B& B::Type1 = GlobalType1;
const B& B::Type2 = GlobalType2;
Это ошибка компилятора или стандартынарушение в коде?