C ++ 17 и расширение ссылки на статическое временное время жизни - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть некоторый код, который пытается выполнить своего рода одноэлементный полиморфизм, например так:

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

Это ошибка компилятора или стандартынарушение в коде?

1 Ответ

0 голосов
/ 27 сентября 2018

Поскольку в комментариях кажется, что это действительно ошибка компилятора, я сообщил о проблеме .

Оставив вопрос открытым на некоторое время, показаключен.

...