У меня есть код, который пытается выполнить своего рода одноэлементный полиморфизм, например:
// 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 в режим компиляции С++ 17, то (без каких-либо предупреждений компилятора) произойдет сбой во время выполнения, потому что какой-то конкретный const B*
указывает на объект, который имеет совершенно не связанную виртуальную таблицу, т.е. что-то растоптало память, которая должна была быть зарезервирована для одного из экземпляров. Я предполагаю, что это означает, что временное было уничтожено слишком рано.
Я могу заставить это вести себя так, как ожидалось, избегая использования временного:
static const D1 GlobalType1;
static const D2 GlobalType2;
const B& B::Type1 = GlobalType1;
const B& B::Type2 = GlobalType2;
Это ошибка компилятора или нарушение стандартов в коде?
constexpr void f(void) { }
по сравнению сconstexpr void f() { }
как регрессию, все возможно. - person Tanveer Badar   schedule 26.09.2018