Итак, вы используете «инициализацию копирования»:
8.5/11 Инициализаторы
Форма инициализации (с использованием круглых скобок или =) обычно не имеет значения, но имеет значение, когда инициализируемый объект имеет тип класса; увидеть ниже. ...
Инициализация, которая происходит при передаче аргумента, возврате функции, генерации исключения (15.1), обработке исключения (15.3) и списках инициализаторов, заключенных в фигурные скобки (8.5.1), называется инициализацией копированием и эквивалентна форме
T x = a;
Инициализация, которая происходит в новых выражениях (5.3.4), выражениях static_cast (5.2.9), преобразованиях типов функциональной нотации (5.2.3) и инициализаторах базы и члена (12.6.2), называется прямой инициализацией и эквивалентна форма
T x(a);
В 13.3.1.3 «Инициализация конструктором» перегружены для выбранного конструктора:
Когда объекты типа класса инициализируются напрямую (8.5) или инициализируются копированием из выражения того же типа или типа производного класса (8.5), разрешение перегрузки выбирает конструктор. Для прямой инициализации функциями-кандидатами являются все конструкторы класса инициализируемого объекта. Для инициализации копирования функциями-кандидатами являются все конструкторы преобразования (12.3.1) этого класса.
Таким образом, для инициализации копирования должен быть доступен конструктор копирования. Однако компилятору разрешено «оптимизировать» копию:
12.2/1 Временные объекты
Даже когда создание временного объекта избегается (12.8), все семантические ограничения должны соблюдаться, как если бы временный объект был создан. [Пример: даже если конструктор копирования не вызывается, все семантические ограничения, такие как доступность (пункт 11), должны быть удовлетворены. ]
Вы можете получить желаемый эффект, избегая инициализации копирования и используя прямую инициализацию:
const A &b(B());
Примечание:
Поскольку более новые версии GCC, по-видимому, имеют другое поведение, я решил опубликовать эту заметку, которая может устранить разницу (при этом оба поведения по-прежнему соответствуют стандартам):
8.5.3/5 Ссылки говорят:
Если выражением инициализатора является rvalue с T2 типом класса, а «cv1 T1» совместим по ссылке с «cv2 T2», ссылка связывается одним из следующих способов (выбор определяется реализацией):
Ссылка привязана к объекту, представленному значением r (см. 3.10), или к подобъекту внутри этого объекта.
Создается временный объект типа «cv1 T2» [так в оригинале], и вызывается конструктор для копирования всего объекта rvalue во временный объект. Ссылка привязана к временному объекту или к подобъекту во временном объекте.
Конструктор, который будет использоваться для создания копии, должен вызываться независимо от того, действительно ли копия выполнена.
Первоначально я прочитал последнее предложение ("конструктор, который будет использоваться..."), чтобы применить его к обоим параметрам, но, возможно, его следует читать как применимый только к параметру секунд - или, по крайней мере, может быть, так читают сопровождающие GCC. Это.
Я не уверен, что это то, что происходит между разным поведением версий GCC (комментарии приветствуются). Мы определенно достигли предела моих языковых навыков...
person
Michael Burr
schedule
14.07.2010