Здравствуйте, Elija, Вы писали:
E>3) Как я понимаю, инициализация списком использует или direct-list-initialization или copy-list-initialization.
E>8.5.4 List-initialization
Это не то. Инициализация массивов описана в dcl.init.aggr. В принципе там описано, что если элементы массива не агрегаты, то для них будет выполняться copy-initialized from the corresponding initializer-clause. То есть компилятор может сначала сконструировать элементы типа B, а потом их скопировать в arrB (на самом деле не может
), что без конструктора копирования или конструктора перемещения сделать нельзя. Конструктор копирования у тебя удалён, а вот добавление перемещающего спасает дело.
Ну и как уже заметили, автогенерация конструкторов и copy ellision просто всё запутывают.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Elija, Вы писали:
К>Критичным для gcc является нетривиальный деструктор у B — из-за нетривиального деструктора у queue<C>. К>Можно упростить: К>
У меня два компилятора:
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
Microsoft Visual Studio 2015 ver. 14.0. (Visual C++ 2015)
Просто код для примера:
#include <queue>
class C
{
};
class B
{
public:
// assignment and copy prohibited
B(const B&) = delete;
B& operator=(const B&) = delete;
B(int v1, int v2) : m_V1(v1), m_V2(v2) {}
private:
int m_V1;
int m_V2;
std::queue<C> m_Queue;
};
class A
{
public:
// assignment and copy prohibited
A(const A&) = delete;
A& operator=(const A&) = delete;
A(int p1, int p2) : arrB{ {p1+1, p2+2}, {p1+3, p2+4}, {p1+5, p2+6} } { }
private:
B arrB[3];
};
1) Если я использую g++ и
std::queue<C> m_Queue;
то я получаю следующую ошибку:
make
g++ -std=c++11 -c test.cpp
test.cpp: In constructor ‘A::A(int, int)’:
test.cpp:29:70: error: use of deleted function ‘B::B(const B&)’
A(int p1, int p2) : arrB{ {p1+1, p2+2}, {p1+3, p2+4}, {p1+5, p2+6} } { }
^
test.cpp:11:3: error: declared here
B(const B&) = delete;
^
make: *** [test.o] Error 1
2) Если же я использую тот же g++, но комментирую линию кода
//std::queue<C> m_Queue;
или если я использую оба варианта (раскомментировано и закомментировано) с Microsoft Visual Studio 2015, то я не получаю никаких ошибок.
3) Как я понимаю, инициализация списком использует или direct-list-initialization или copy-list-initialization.
8.5.4 List-initialization
1 List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, and the comma-separated initializer-clauses of the list are called the elements of the initializer list. An initializer list may be empty. List-initialization can occur in direct-initialization or copyinitialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization.
Но, видимо, я не понимаю какой из видов инициализации будет использован в моём случае. Я предполагал, что должна использоваться direct-list-initialization в соответствии с http://en.cppreference.com/w/cpp/language/list_initialization (вариант (5) по этой ссылке, вариант (9) — не то, поскольку это "a user-defined operator[]"). Но тогда причём тут недоступный конструктор копирования? И какая связь с наличием экземпляра очереди в классе?
Может мне кто-то подробно объяснить эту ситуацию и в чём я ошибаюсь и какой компилятор прав?
Здравствуйте, Elija, Вы писали:
E>какая связь с наличием экземпляра очереди в классе?
Думаю, наличие нетривиального члена запрещает создание move-конструктора
Здравствуйте, dead0k, Вы писали:
E>>какая связь с наличием экземпляра очереди в классе? D>Думаю, наличие нетривиального члена запрещает создание move-конструктора
А почему там должен использоваться конструктор перемещения? Если можно поподробнее со ссылкой на источник.
И это не отменяет вопроса почему g++ жалуется на недоступный конструктор копирования и кто из компиляторов прав...
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, Elija, Вы писали:
E>>3) Как я понимаю, инициализация списком использует или direct-list-initialization или copy-list-initialization.
E>>8.5.4 List-initialization W>Это не то. Инициализация массивов описана в dcl.init.aggr. В принципе там описано, что если элементы массива не агрегаты, то для них будет выполняться copy-initialized from the corresponding initializer-clause. То есть компилятор может сначала сконструировать элементы типа B, а потом их скопировать в arrB, что без конструктора копирования или конструктора перемещения сделать нельзя. Конструктор копирования у тебя удалён, а вот добавление перемещающего спасает дело.
W>Ну и как уже заметили, автогенерация конструкторов и copy ellision просто всё запутывают.
W>Короче, избавься от агрегата: W>
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, Elija, Вы писали:
E>>3) Как я понимаю, инициализация списком использует или direct-list-initialization или copy-list-initialization.
E>>8.5.4 List-initialization W> Конструктор копирования у тебя удалён, а вот добавление перемещающего спасает дело.
Получается, добавив один конструктор копирования руками и пометив его как delete мы отключаем автогенерацию конструктора перемещения?
Здравствуйте, watchmaker, Вы писали: W>Конструктор копирования у тебя удалён, а вот добавление перемещающего спасает дело.
Похоже, что есть что-то еще. Я запретил все конструкторы копирования/операторы присваивания, но не смог добиться ошибки компиляции в случае тривиального класса (без очереди): http://ideone.com/ieCuiI
Здравствуйте, Kernan, Вы писали:
K>Получается, добавив один конструктор копирования руками и пометив его как delete мы отключаем автогенерацию конструктора перемещения?
Конструктор перемещения можно вернуть написав: " = default;":
Здравствуйте, dead0k, Вы писали:
D>Здравствуйте, watchmaker, Вы писали: W>>Конструктор копирования у тебя удалён, а вот добавление перемещающего спасает дело.
D>Похоже, что есть что-то еще. Я запретил все конструкторы копирования/операторы присваивания, но не смог добиться ошибки компиляции в случае тривиального класса (без очереди): D>http://ideone.com/ieCuiI
Да, опять непонятно... То есть в каких-то случаях элементы массива copy-initialized from the corresponding initializer-clause, а в каких-то нет? И что это за случаи?
Здравствуйте, dead0k, Вы писали:
D>Думаю, наличие нетривиального члена запрещает создание move-конструктора
А разве у std::deque нет move-конструктора?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Elija, Вы писали:
E>Да, опять непонятно... То есть в каких-то случаях элементы массива copy-initialized from the corresponding initializer-clause, а в каких-то нет?
Выше я неверно написал. Там конечно хоть и происходит copy-initialization, но по стандарту copy-initialization должен успешно срабатывать если доступен не explicit конструктор с аргументами, принимающими соответствующий expression-list (а наличие или отсутствие конструктора копирования после этого уже не важно). То есть твой код валиден, а ошибка в gcc. Легко тригеррится, если класс не trivially destructible (а включение std::queue к этому тоже приводит). Ну а обход проблемы через std::array работает по прежнему из-за того, что там нет агрегатной инициализации.
Здравствуйте, watchmaker, Вы писали:
W> В принципе там описано, что если элементы массива не агрегаты, то для них будет выполняться copy-initialized from the corresponding initializer-clause.
Упорото как-то, почему на месте собрать элементы нельзя?
W>Обойти можно избавившись от агрегата: W> std::array<B, 3> arrB;
Хм, вот ещё одно преимущество защищённого массива перед сырым. Правда, я уже не понимаю, почему так, внутри-то там тот же сырой массив в привате.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
W>> В принципе там описано, что если элементы массива не агрегаты, то для них будет выполняться copy-initialized from the corresponding initializer-clause.
TB>Упорото как-то, почему на месте собрать элементы нельзя?
Называется оно упорото: по факту оказывается, что copy-initialization совсем не запрещает делать инициализацию по месту, а наоборот — в приведённом коде copy-initialization не должно делать никаких копирований даже несмотря на наличие copy в названии.