Я заметил непоследовательное поведение в моем рабочем коде C++17 в отношении общих лямбда-выражений и примечаний. Наконец мне удалось разбить это на следующий минимальный пример.
Выдает примечание с x86_64 gcc 9.3, но НЕ с x86_64 gcc 10.1.
#include <string>
#include <iostream>
struct STR { int a; };
int main()
{
auto lambda =
[]( const auto& executionContext )
{
if ( !executionContext.empty() )
return;
STR objSTR;
objSTR.a = 666;
std::cout << objSTR.a;
};
lambda( std::string{} );
return 0;
}
Сообщение компилятора следующее:
<source>: In instantiation of 'main()::<lambda(const auto:1&)> [with auto:1 = std::__cxx11::basic_string<char>]':
<source>:19:31: required from here
<source>:4:12: note: 'struct STR' has no user-provided default constructor
4 | struct STR { int a; };
| ^~~
<source>:4:22: note: and the implicitly-defined constructor does not initialize 'int STR::a'
4 | struct STR { int a; };
| ^
Чем хороша заметка? Я правильно инициализирую свою структуру с помощью 666. Насколько мне известно, это правильный код C++ и не требует каких-либо примечаний/ссылок о/на возможные неинициализированные опасности.
Интересно, что если я сейчас заменю auto
на std::string
, заметка исчезнет полностью. Так вдруг здесь не нужна никакая заметка?
Не дает никаких примечаний с x86_64 gcc 9.3 и с x86_64 gcc 10.1.
#include <string>
#include <iostream>
struct STR { int a; };
int main()
{
auto lambda =
[]( const std::string& executionContext )
{
if ( !executionContext.empty() )
return;
STR objSTR;
objSTR.a = 666;
std::cout << objSTR.a;
};
lambda( std::string{} );
return 0;
}
Я могу ТОЛЬКО избавиться от примечания для общей лямбды, если использую инициализацию значения следующим образом:
Не дает никаких примечаний с x86_64 gcc 9.3 и с x86_64 gcc 10.1.
#include <string>
#include <iostream>
struct STR { int a; };
int main()
{
auto lambda =
[]( const auto& executionContext )
{
if ( !executionContext.empty() )
return;
STR objSTR{}; //FORCED to add {} to get rid of the note
objSTR.a = 666;
std::cout << objSTR.a;
};
lambda( std::string{} );
return 0;
}
На мой взгляд, это похоже на ошибку, когда в контексте шаблона, такого как общая лямбда-выражение, вы внезапно вынуждены использовать инициализацию значения для простой структуры, когда вы не хотите иметь эту заметку. Тот факт, что это примечание больше не появляется в таком контексте, как в GCC 10.1, для меня подчеркивает аргументацию.
Конкретный, однозначный вопрос:
=> Можете ли вы подтвердить, что это ошибка в GCC 9.3?
Онлайн-демо: https://godbolt.org/z/E7xeP91xd
Флаги: -Wall -Wextra -O3 -std=c++17
Компилятор: x86_64 gcc 9.3/x86_64 gcc 10.1
gcc прав в том, что говорит. Почему вы думаете, что это не так? Созданный компилятором конструктор не инициализирует член.
Я скорректировал свой пост. Но это также противоречивое поведение для заметок.
В вашем примере я не вижу проблемы с отсутствующей заметкой, потому что этот член никогда не читается. Однако gcc 10.1 не выдает никаких результатов даже при использовании члена godbolt.org/z/8Eqj4n5hM
Я думаю, ты еще не совсем понял суть. Я думаю, что должна быть возможность создать экземпляр структуры БЕЗ инициализации ее напрямую с помощью {} без этого примечания. Однако это невозможно в универсальной лямбде в gcc 9. За пределами универсальной лямбды совершенно нормально НЕ использовать {}. Здесь вы не получите НИКАКОЙ записки. Так почему же примечание отсутствует за пределами общей лямбды и почему оно полностью отсутствует в gcc10? godbolt.org/z/6WGar76W1
Я до сих пор не понимаю, что плохого в создании этой заметки. И я не понимаю, как я могу упустить момент, который вы только сейчас затронули? За пределами лямбды нет неинициализированного члена. хм? Должно быть, такая сегодня погода.
Примечание представляет собой неоправданный шум. Меня беспокоит то, что я получаю подсказки (и только в контексте шаблона), что мой POD имеет неинициализированные значения, хотя впоследствии я инициализирую все значения. GCC10, кажется, устранил этот шум. Ты все еще не видишь?
Я еще раз немного отредактировал свой пост, чтобы, возможно, было яснее, что имеется в виду.
@SoulfreezerXP В самом предупреждении нет ничего плохого. Компиляторы выдают их постоянно, например, «предупреждение: неиспользуемая переменная» и т. д. Компиляторы могут предупреждать.
Я действительно очень упускаю суть этого вопроса. Ни одна из версий GCC не является новой. Ни одна из версий не является ошибочной. Менее древняя версия немного более последовательна. Это могло быть совершенно непреднамеренно и, следовательно, не в журнале изменений.
Пожалуйста, прочитайте вопрос и ответьте или нет....но не голосуйте против ради развлечения. Я хочу знать, является ли это плохим поведением или нет.
@MSalters адаптировал вопрос для вас
@SoulfreezerXP Вопрос будет закрыт как основанный на мнении, если вы используете такие слова, как «это некрасиво». Теперь, чтобы сейчас ответить на ваш вопрос «Это ошибка?» Нет, это не ошибка. Составители могут предупредить. Возможно, вы видели такие предупреждения, как предупреждение: переменная объявлена, но не используется... и т. д. Все эти предупреждения являются действительными, и компиляторы могут их предупредить.
Здесь нет никаких предупреждений, только неуместные ПРИМЕЧАНИЯ. И это создает ненужный шум в моем контексте, поскольку я правильно инициализирую свою структуру.
@SoulfreezerXP Вы сказали «предупреждение» в заголовке своего вопроса.
Это был не я. Наверное, кто-то другой неправильно адаптировал название. Я исправлю заголовок. Но из 1-го и 2-го моего комментария 6 часов назад должно быть понятно, что речь идет о заметках! И да, бросание заметки без надобности тоже может быть «багом».
@SoulfreezerXP Возможно, именно поэтому они удалили его из поздних версий.
Возможно, но я хочу быть уверенным и получить ответ от профессионала.
@SoulfreezerXP Думаю, тогда официальная страница gcc подошла бы больше.
Примечание в GCC 9.3 о неинициализированном члене в структуре STR технически правильно, поскольку конструктор по умолчанию не инициализирует int a.
В GCC 10.1 эта проверка, возможно, была смягчена или улучшена распознавание контекста для общих лямбда-выражений. Инициализация objSTR с помощью {} — хорошая практика для обеспечения инициализации членов. Если примечание раздражает, но безвредно, вы можете спокойно проигнорировать его или явно инициализировать структуру. Различные версии компилятора часто имеют различия в поведении предупреждений и примечаний, что может объяснить наблюдаемое несоответствие.
Я принимаю это как ответ, потому что это, по крайней мере, в некоторой степени отвечает на вопрос.
Разве GCC 9.3 не ведет себя здесь неправильно? Я понимаю, что моя структура не инициализируется
int STR::a
Нет, компилятору разрешено выдавать диагностику (включая предупреждение), даже если вы не используете неинициализированный член нигде в своей программе.
Вы говорите «сообщение об ошибке», но это не сообщение об ошибке. Программа все еще компилируется. Это даже не похоже на предупреждение. Кажется, gcc 9 просто болтал о потенциально интересных вещах, которые он нашел.