С++ 11 гарантирует, что "int a [8] = {};" семантически эквивалентно "int a [8] {};"? - программирование
Подтвердить что ты не робот

С++ 11 гарантирует, что "int a [8] = {};" семантически эквивалентно "int a [8] {};"?

В С++ 11 оба следующих утверждения являются законными:

1. int a[8] = {};

2. int a[8]{};

Однако, мне нравится утверждение 1 лучше, чем утверждение 2, потому что я считаю, что оператор 1 более выразителен.

Стандарт С++ 11 гарантирует, что оба оператора семантически эквивалентны?

4b9b3361

Ответ 1

Семантически, они не то же самое, что и копирование/прямая инициализация:

8.5.4 List-initialization [dcl.init.list]

1 Инициализация списка - это инициализация объекта или ссылки из скопированного списка инициализации. Такой инициализатор называемый списком инициализаторов, и разделяемые запятыми инициализаторы-предложения списка называются элементами список инициализаторов. Список инициализаторов может быть пустым. Инициализация списка может возникать при прямой инициализации или copyinitialization контексты; инициализация списка в контексте прямой инициализации называется инициализацией прямого списка и list-initialization в контексте инициализации копирования называется copy-list-initialization. [...] (выделено мной)

Оригинальный ответ, касающийся сравнительной производительности: Нет, стандарт указывает некоторые ограничения сложности на алгоритмы, но не производительность по таким вопросам. Это лучше оставить компилятору, но все компиляторы, скорее всего, сгенерируют один и тот же код.

Подумайте о инициализации копирования и прямой инициализации. Стандарт определяет только то, что они есть, он никогда не говорит, что нужно быть быстрее, чем другое, или что они должны вести себя одинаково. Это полностью зависит от компилятора.

И это хорошо, потому что компилятор знает, что лучше всего подходит для этой платформы. Если бы стандарт налагал такие ограничения, можно сказать, что + должен быть быстрее, чем *, что довольно интуитивно понятен. Но подумайте о платформе, построенной для умножения, где она быстрее вычисляет * в машинный код. Компилятор должен был бы отказаться от своего перевода, чтобы перевести * в более медленную инструкцию, чтобы соответствовать стандартам.

Ответ 2

Стандарт определяет только так называемое "наблюдаемое поведение", которое представляет собой последовательность вызовов библиотеки ввода-вывода, а также чтение и запись изменчивых данных. Нет требований скорости.

Вы не можете быть уверены, что на практике быстрее. Достойные компиляторы должны испускать один и тот же код, но иногда есть ошибки в компиляторах, и это может повлиять на эмиссию кода.

Ответ 3

Да, они семантически эквивалентны.

Инициализация списка (8.5.4) в совокупности (8.5.1, например массив) выполняет агрегатную инициализацию (8.5.4p3b1). Совокупная инициализация не волнует, является ли синтаксическая форма прямой инициализацией или инициализацией копии; правила агрегатной инициализации применяются одинаково в любом случае. В частности, члены агрегата всегда копируются из соответствующего предложения списка инициализаторов.

Есть исключение, которое почти, но не совсем применимо в вашем случае; где недостаточно элементов для инициализации всех членов совокупности, стандарт неясен о том, как инициализировать оставшихся членов; они инициализируются списком из {} (пустой инициализатор списка), но не указаны, являются ли они инициализированы или инициализированы с помощью списка-списков, или это зависит от первоначальной инициализации списка (см. комментарии); на самом деле, clang и gcc отличаются поведением в этом краевом случае. Однако это не имеет значения в вашем случае, так как тип агрегатного элемента int, а для типов nonclass-list-initialization из {} вызывает инициализацию значения, то есть инициализацию нуля, которая является прямой независимо от синтаксической формы (т.е. int i{}; и int i = {}; являются семантически идентичными).

Есть несколько причин предпочесть синтаксис = (copy-initialization): во-первых, это форма, используемая стандартом почти во всех примерах (исключения являются последними двумя примерами в 8.5.4p3, где один демонстрирует ошибку в сужении преобразования, а другая демонстрирует инициализацию из пустого списка инициализаторов). Кроме того, как вы сказали, это более выразительно; Я также обнаружил, что при инициализации списка агрегатов, синтаксис копирования-инициализации лучше отражает тот факт, что элементы агрегата сами инициализируются копированием.

Наконец, синтаксис без = необходим в одном случае: где объект является неагрессивным типом класса с конструктором explicit. Таким образом, синтаксис с прямым списком-инициализацией должен быть зарезервирован для этого случая.

Ответ 4

Стандарт С++ 11 даже не гарантирует, что int a[8] = {}; работает так же быстро, как int aVeryLongName[8] = {};.