Почему мне не предоставляется конструктор копирования по умолчанию из volatile?

Этот код:

class X {
  int member;  
};

volatile X a;
X b = a;

Сбой с ошибкой:

prog.cpp:6:7: error: no matching function for call to ‘X::X(volatile X&)’
prog.cpp:6:7: note: candidates are:
prog.cpp:1:7: note: X::X()
prog.cpp:1:7: note:   candidate expects 0 arguments, 1 provided
prog.cpp:1:7: note: X::X(const X&)
prog.cpp:1:7: note:   no known conversion for argument 1 from ‘volatile X’ to ‘const X&’

Можно ли как-нибудь заставить компилятор сгенерировать конструктор энергозависимых копий для меня?

2 ответа

Решение

Короткий ответ: потому что стандарт говорит, что вы не будете.

Стандарт C++ 12.8/9 (проект N3242) сообщает:

Неявно объявленный конструктор копирования для класса X будет иметь вид

  • X::X(const X&)

если

  • каждый прямой или виртуальный базовый класс B из X имеет конструктор копирования, первый параметр которого имеет тип const B& или const volatile B&, и
  • для всех нестатических членов данных X, которые имеют тип класса M (или его массив), каждый такой тип класса имеет конструктор копирования, первый параметр которого имеет тип const M& или const volatile M &. [Примечание: 119]

В противном случае неявно объявленный конструктор копирования будет иметь вид

  • X::X(X&)

Примечание 119 говорит:

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

В С.1.9 вы найдете:

Неявно объявленный конструктор копирования и неявно объявленный оператор присваивания копии не могут сделать копию изменчивого lvalue. Например, в ISO C действует следующее:

struct X { int i; };
volatile struct X x1 = {0};
struct X x2(x1); // invalid C++
struct X x3;
x3 = x1; // also invalid C++

Обоснование: несколько альтернатив были обсуждены подробно. Изменение параметра на volatile const X& значительно усложнит генерацию эффективного кода для объектов класса. Обсуждение предоставления двух альтернативных сигнатур для этих неявно определенных операций вызвало нерешенную озабоченность по поводу создания неоднозначностей и усложнения правил, которые определяют формирование этих операторов в соответствии с основаниями и членами.

Основная проблема заключается в том, что вы не предоставляете конструктор присваивания. Следовательно, компилятор сгенерирует по умолчанию для вас:

X& X::operator =(const X& x){
   this.member = x.member;
   return *this;
}

Конструктор присваивания по умолчанию принимает тип аргумента как const X&, в котором const является const низкого уровня и не будет игнорироваться как const верхнего уровня.

Ваш код X b = a означает вызвать конструктор по умолчанию. Но твой аргумент a имеет тип volatile X (может быть преобразован в volatile X & и volatile const X&) не может быть преобразован в const X& неявно.

Таким образом, вы должны определить свой собственный конструктор присваивания как

X& X::operator =(volatile const X&);

РЕДАКТИРОВАТЬ
Меня шокирует, что многие считают, что при использовании оператора присваивания вызывается конструктор копирования (или инициализация копирования вызова). Может быть, называть это оператором присваивания не часто. Однако меня волнует, какой метод вызывается.

Вы можете сослаться на этот пост: Копировать конструкторы, операторы присваивания, безопасное назначение исключений и Оператор присваивания по умолчанию


РЕДАКТИРОВАТЬ
Я сделал ошибку ранее. X b = a это просто процесс инициализации. Нет назначения не участвует. Извиняюсь за мое сообщение об ошибке.

Другие вопросы по тегам