Рассмотрим следующий код:
class A {
A(const A&);
public:
A() {}
};
int main() {
const A &a = A();
}
Этот код прекрасно компилируется с GCC 4.7.2, но не компилируется с Visual C ++ 2010 со следующей ошибкой:
test.cc(8) : error C2248: 'A::A' : cannot access private member declared in class 'A'
test.cc(2) : see declaration of 'A::A'
test.cc(1) : see declaration of 'A'
Так необходимо ли иметь конструктор копирования, доступный при привязке временного к ссылке?
Это связано с моим предыдущим вопросом:
Есть ли способ отключить привязку временного к константной ссылке?
Так необходимо ли иметь конструктор копирования, доступный при привязке временного к ссылке?
Пост C ++ 11 — Нет
Pre C ++ 11 — Да.
Этот код прекрасно компилируется с GCC 4.7.2, потому что он соответствует стандарту C ++ 11.
Стандарт C ++ 11 предписывает, что когда ссылка на const инициализируется из prvalue
, он должен быть привязан непосредственно к эталонному объекту, и временное создание запрещено. Кроме того, конструктор копирования не используется или не требуется.
До C ++ 11 правила были другими. И это поведение (будет ли вызываться конструктор копирования) определяется реализацией. C ++ 03 позволял вызывать конструктор копирования при привязке константной ссылки к временной, и, следовательно, после C ++ 11 конструктор копирования должен быть доступен. Visual C ++ 2010 соответствует стандарту C ++ 03.
Раздел 8.5.3.5 стандарта C ++ 03 гласит, что это определяется реализацией:
Если выражение инициализатора является r-значением, с T2 типом класса, и «cv1 T1» совместим со ссылками с «cv2 T2», ссылка связывается одним из следующих способов (выбор определяется реализацией):
— Ссылка привязана к объекту, представленному значением r (см. 3.10), или к подобъекту в этом объекте.
— Создается временный объект типа «cv1 T2» [sic], и вызывается конструктор для копирования всего объекта rvalue во временный объект. Ссылка привязана к временному или подобъекту во временном.
Конструктор, который будет использоваться для создания копии, должен вызываться независимо от того, выполняется ли копия на самом деле.
Таким образом, похоже, что обе реализации соответствуют стандарту C ++ 03.
Последнее предложение немного сбивает с толку, но то, как я его читаю, означает, что реализация может выбрать второй путь, но все же оптимизировать копию. В этом случае конструктор копирования должен быть доступен, даже если копия на самом деле не была сделана, аналогично оптимизации возвращаемого значения.
Со стандартом C ++ 11, второй способ больше не вариант.
Visual C ++ неверен; Стандарт не указывает, что конструктор копирования должен быть доступен для привязки const
ссылка на временную.