c ++ 11 — Как на C ++ синтезированный конструктор перемещения влияют изменчивые и виртуальные члены?

Посмотрите на следующий код:

struct node
{

node();
//node(const node&);    //#1
//node(node&&);         //#2

virtual                 //#3
~node ();

node*
volatile                //#4
next;

};

int main()
{

node m(node());         //#5
node n=node();          //#6
}

При компиляции с gcc-4.6.1 выдает следующую ошибку:

g++ -g --std=c++0x   -c -o node.o node.cc
node.cc: In constructor node::node(node&&):
node.cc:3:8: error: expression node::next has side-effects
node.cc: In function int main():
node.cc:18:14: note: synthesized method node::node(node&&) first required here

Как я понимаю, компилятору не удается создать конструктор перемещения или копирования по умолчанию в строке № 6, если я раскомментирую строку № 1 или № 2, он компилируется нормально, это ясно. Код прекрасно компилируется без опции c ++ 0x, поэтому ошибка связана с конструктором перемещения по умолчанию.

Однако что в классе узла препятствует созданию конструктора перемещения по умолчанию? Если я прокомментирую какую-либо из строк № 3 или № 4 (то есть сделаю деструктор не виртуальным или сделаем элемент данных энергонезависимым), он снова скомпилирует, так что комбинация этих двух не позволяет его компилировать?

Еще одна загадка, строка № 5, не вызывает ошибку компиляции, чем она отличается от строки № 6?
Это все специфично для gcc? или gcc-4.6.1?

10

Решение

[C++11: 12.8/9]: Если определение класса X явно не объявляет конструктор перемещения, он будет неявно объявлен как дефолт, если и только если

  • X не имеет объявленного пользователем конструктора копирования,
  • X не имеет заявленного пользователем оператора копирования,
  • X не имеет объявленного пользователем оператора назначения перемещения,
  • X не имеет объявленного пользователем деструктора, а также
  • конструктор перемещения не будет неявно определен как удаленный.
[ Замечания: Когда конструктор перемещения не объявлен явно или не предоставлен явно, выражения, которые в противном случае
вызвал бы конструктор перемещения, может вместо этого вызвать конструктор копирования. —Конечная записка]

Вот почему ваш № 3 нарушает синтез.

К тому же, это далеко не ясно тот изменчивые типы (в том числе ваш node* volatile) тривиально копируемые; можно сделать вывод, что это определяется реализацией, являются ли они или нет и, в вашем случае, кажется, что это не так.

По крайней мере, GCC заставил его перестать работать вполне сознательно в v4.7, с предложением перенести обратно в v4.6.1, что я могу только предположить, пошел вперед …

Итак, учитывая следующее:

[C++11: 12.8/11]: Неявно объявленный конструктор копирования / перемещения является встроенным открытым членом своего класса. По умолчанию конструктор копирования / перемещения для класса X определяется как удаленный (8.4.3), если X имеет:

  • вариант члена с нетривиальным соответствующим конструктором и X это союзный класс,
    нестатический член данных типа класса M (или их массив), которые нельзя скопировать / переместить из-за разрешения перегрузки (13.3) применительно к MСоответствующий конструктор, приводит к неоднозначности или функции, которая удалена или недоступна из конструктора по умолчанию,
  • прямой или виртуальный базовый класс B которые нельзя скопировать / переместить из-за разрешения перегрузки (13.3) применительно к BСоответствующий конструктор, приводит к неоднозначности или функции, которая удалена или недоступна из конструктора по умолчанию,
  • любой прямой или виртуальный базовый класс или нестатический член данных типа с деструктором, который удален или недоступен из конструктора по умолчанию,
  • для конструктора копирования — нестатический член данных ссылочного типа rvalue или
  • для конструктора перемещения — нестатический элемент данных или прямой или виртуальный базовый класс с типом, который не имеет конструктора перемещения и не является легко копируемым.

… Вот почему ваш № 4 нарушает синтез, независимо от № 3.

Что касается # 5, это на самом деле не декларация node вообще, но объявление для функции с именем m — поэтому он не воспроизводит симптомы, связанные с node (это известно как Most Vexing Parse).

12

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]