Ссылка на этот указатель: GCC vs clang

Это продолжение эти вопросы.

Рассмотрим следующий код:

struct A {
private:
    A* const& this_ref{this};
};

int main() {
    A a{};
    (void)a;
}

Если скомпилировано с -Wextra, как GCC v6.2, так и clang v3.9 показать предупреждение.

Во всяком случае, с немного измененной версией, показанной ниже, они ведут себя по-другому:

struct A {
    A* const& this_ref{this};
};

int main() {
    A a{};
    (void)a;
}

В этом случае GCC не выдает никаких предупреждений, clang выдает то же предупреждение, что и в предыдущем примере.

Предупреждения практически идентичны.
Оно следует из clang:

3: предупреждение: привязка элемента ссылки this_ref к временному значению [-Wdangling-field]

Какой компилятор прав?

Я бы сказал, что GCC ошибается в этом случае, и я открывал проблему, но, возможно, все наоборот из-за загадочного углового регистра языка.


person skypjack    schedule 12.09.2016    source источник
comment
Два примера кажутся идентичными. Также вы не представили предупреждение.   -  person Cheers and hth. - Alf    schedule 12.09.2016
comment
@Cheersandhth.-Альф Разница private:. Но показать настоящие предупреждения было бы действительно хорошо.   -  person hyde    schedule 12.09.2016
comment
@Cheersandhth.-Alf Примеры отличаются для private, и я собираюсь добавить предупреждение, потому что вы действительно правы.   -  person skypjack    schedule 12.09.2016
comment
@hyde Добавлено предупреждение. Спасибо.   -  person skypjack    schedule 12.09.2016
comment
По-настоящему странно то, что это соединяет две несвязанные части языка. private: — это ограничение поиска имени, и здесь оно применяется к поиску имени this_ref. Временное значение — this, но оно не используется в контексте, где нужно искать имя this_ref.   -  person MSalters    schedule 12.09.2016
comment
@skypjack: европейская раскладка клавиатуры, обратная галочка ` также используется для постановки ударения на гласных. Например. а. Но исправлено сейчас.   -  person MSalters    schedule 12.09.2016
comment
@MSalters Я из Италии. Я действительно привык использовать эти клавиатуры. :-)   -  person skypjack    schedule 12.09.2016


Ответы (3)


Причиной этого предупреждения является IMO, эта выдержка из стандарта (12.2.5):

Временная привязка к элементу ссылки в ctor-initializer конструктора (12.6.2) сохраняется до выхода из конструктора.

а поскольку ключевое слово this является выражением prvalue, во время this_ref инициализации временное значение будет создан и this_ref привязан к этому временному.

Но я сомневаюсь, что ваша ссылка действительно инициализирована в ctor-initializer.

Если вы пишете:

struct A {
private:
    const int& rr = 1+1;
};

то вы воспроизведете точно такую ​​же проблему с gcc, удаление приватного также удалит это предупреждение.

Из того, что я знаю, this pointer может использоваться в теле нестатической функции-члена, я никогда не читал, что его можно использовать в качестве аргумента во время инициализации члена по умолчанию.

person marcinj    schedule 12.09.2016

Декларация члена

A* const& this_ref{this};

привязывает ссылку к временному объекту, который существует только во время выполнения конструктора (примечание: this — это выражение rvalue).

Я не уверен, что this формально доступен в этом контексте, но если это так, то при любом использовании этого указателя у вас серьезный случай UB.

Re

Какой компилятор подходит?

компилятор может выдать столько диагностических сообщений, сколько захочет. Неправильно делать диагностику. Итак, согласно вашему описанию, оба принимают код, тогда либо оба компилятора правы (что, я думаю, наиболее вероятно), либо оба ошибаются.

person Cheers and hth. - Alf    schedule 12.09.2016
comment
Они оба выдают предупреждение в одном случае, но не в другом. Я могу согласиться с тем, что диагностика бесплатна, но здесь как минимум отсутствует последовательность. - person skypjack; 12.09.2016

this – это prvalue, а временный объект будет создан при привязке ссылки к prvalue, поэтому вы привязываете элемент ссылки к временному в инициализатор элемента по умолчанию.

И привязка ссылочного элемента к временному в инициализаторе элемента по умолчанию имеет неправильный формат, что явно указано в стандарте.

$12.6.2/11 Инициализация баз и элементов [class.base.init]:

Временное выражение, связанное со ссылочным элементом из инициализатора элемента по умолчанию, имеет неверный формат. [ Пример:

struct A {
  A() = default;          // OK
  A(int v) : v(v) { }     // OK
  const int& v = 42;      // OK
};
A a1;                     // error: ill-formed binding of temporary to reference
A a2(1);                  // OK, unfortunately

— конец примера]

И см. CWG 1696, это относится к C+ +14.

person songyuanyao    schedule 12.09.2016