Ответ 1
Первый вызов вашего пользовательского конструктора для прямой инициализации. Это может иметь побочные эффекты. Следовательно, используется x1
. (Или, по крайней мере, не может быть легко определено, что он не используется.)
Создается вторая копия. Он вызывает ваш пользовательский конструктор для создания временного. Затем он вызывает конструктор копии по умолчанию для построения x2
. (См. Ниже в edit для более подробного обсуждения и уточнения.) Следовательно, x2
можно определить как неиспользуемый, потому что он был создан компилятором-сгенерированным конструктором без побочных эффектов, а сам x2
больше не появляется.
Третий похож на второй. Временное создание создается через созданный пользователем конструктор и затем копируется. Используется временное, но x3
само не является.
См. принятый ответ на этот вопрос: Есть ли разница в С++ между инициализацией и прямой инициализацией?
ИЗМЕНИТЬ
Основываясь на комментариях, вот еще одно обсуждение.
Во-первых, был комментарий, что предупреждение вводит в заблуждение. Это, возможно, несколько субъективно, но я хотел бы указать, что предупреждения такого рода часто предоставляются только на основе "наилучших усилий". Возможно, что что-то, что не гарантируется вообще, верно в конкретном случае, если компилятор будет копать достаточно далеко в проверяемом коде. Однако в какой-то момент разработчики компилятора должны провести линию. Это означает, что вы, как правило, не можете рассчитывать на такое предупреждение, чтобы поймать каждый случай неиспользуемой переменной. (С другой стороны, если у вас есть переменная, которая используется, и вы получите предупреждение, это будет ошибкой.) Мое личное чувство заключается в том, что продемонстрированное здесь поведение не вводит в заблуждение, но, опять же, я вижу, что есть некоторые личные интерпретация при совершении такого вызова.
Во-вторых, @FrançoisAndrieux отметил, что если вы изменили пример, предоставленный OP, чтобы включить пользовательский конструктор копирования, вы все равно получите те же предупреждения. Это ставит под сомнение мое объяснение выше, которое ссылается на конструктор копии по умолчанию. Это касается второй точки теории, которая я последую за конкретным ответом на этот случай. Теоретическая точка зрения заключается в том, что, если вы действительно не захотите вникнуть в сам компилятор и получить свои конкретные правила, проблема заключается в том, может ли компилятор разумно знать, что переменная не используется, имея в виду, что может быть больше одного что компилятор мог прийти к выводу.
В качестве примера, который был изначально опубликован, я думаю, что мой ответ дает возможность, чтобы комплимент мог прийти к его завершению. Другой способ, который, как представляется, применим как к исходной форме, так и к модифицированной форме, предложенной комментарием, основан на копировании. Здесь подробно обсуждаются следующие вопросы: Что такое оптимизация кода и возврат значения?. Ключевым моментом для текущего обсуждения является то, что, в частности, для конструкторов копирования компилятор разрешен игнорировать побочные эффекты. Фактически, в некоторых случаях компилятор должен игнорировать копию. Очевидно, что компилятор здесь учитывает это, прямо или косвенно, при выдаче предупреждения. Это также, вероятно, относится к точке, сделанной OP, что код сборки во всех трех случаях одинаковый - что, поскольку действие копирования было оптимизировано.
Позвольте мне попытаться теперь предвидеть следующий вопрос: "Если копия конструируется, почему не все три случая действительно одинаковы?" Ответ здесь, я думаю, заключается в том, что конкретная переменная не используется. Это неназванные, временные переменные во втором и третьем случае, которые сконструированы, а не именованные переменные x2
и x3
. Временные переменные попадают в один и тот же шаблон, как в первом случае в примере, и "используются" (или, по крайней мере, не могут быть определены достаточно легко, чтобы не использоваться). Это все еще оставляет x2
и x3
неиспользованным любым стандартом после того, как конструкция копии будет оптимизирована.