У меня есть эта функция:
fstream open_user_file() const
{
...
}
но мой компилятор жалуется на fstream
конструктор копирования неявно удаляется. Учитывая, что компилятор выполняет RVO, почему вместо конструктора перемещения выбран конструктор копирования?
В противном случае, каков наилучший способ сделать это?
В настоящее время принятый ответ является просто неправильным.
При возврате локальной переменной с автоматическим хранением того же типа, что и объявленный тип возврата функции, происходит двухфазный процесс:
fstream open_user_file() const
{
fstream f;
/*...*/
return f;
}
Выбор конструктора для копии сначала выполняется, как если бы объект был обозначен значением r.
Если первое разрешение перегрузки не удалось или не было выполнено, или если тип первого параметра выбранного конструктора не является rvalue-ссылкой на тип объекта (возможно, cv-квалифицированный), разрешение перегрузки выполняется снова, рассматривая объект как именующий.
Это означает, что если f
является перемещаемым конструктом, который будет предпочтительным (и, возможно, исключенным) для возвращения f
, Иначе если f
является копируемой конструкцией, которая будет сделана (и, возможно, исключена) для возврата f
, Иначе f
не может быть возвращена из этой функции, и должна произойти ошибка времени компиляции.
Единственный случай, в котором:
return std::move(f);
Должно помочь, когда реализация глючит. В соответствующей реализации, fstream
это движение конструктивно и:
return f;
будет оптимальным. Если f
не двигаться конструктивно, то:
return std::move(f);
не поможет в соответствующей реализации. И если код в любом случае в соответствующей реализации будет иметь эффект пессимизации, то есть он будет тормозить RVO.
В gcc 4.8 не реализованы подвижные потоки (и потоки не подлежат копированию). И это источник вашей проблемы. В C ++ 98, C ++ 03 и gcc 4.8 потоки не могут быть возвращены из функций. В C ++ 11 они есть.
Реализация может опустить операцию копирования, являющуюся результатом оператора return, даже если конструктор копирования имеет побочные эффекты. В этом случае вам, возможно, придется просто явно переместиться.
fstream open_user_file() const
{
fstream f;
/*...*/
return std::move(f);
}
При соблюдении определенных критериев реализация может опустить конструкцию копирования / перемещения класса.
объект, даже если конструктор выбран для операции копирования / перемещения и / или деструктор для объекта
имеют побочные эффекты.
…
И здесь говорится, что конструктор копирования должен быть доступен:
Когда критерии для исключения операции копирования выполнены или будет встречен за исключением того факта, что источник
объект является параметром функции, а копируемый объект обозначается lvalue, разрешение перегрузки до
сначала выберите конструктор для копирования как если бы объект был обозначен значением. Если перегрузка
не удается выполнить разрешение, или если тип первого параметра выбранного конструктора не является ссылкой на значение
тип объекта (возможно, cv-qualified), разрешение перегрузки выполняется снова, рассматривая объект как
именующий. [Примечание: это двухступенчатая перегрузка разрешение должно выполняться независимо от того,
происходят. Он определяет конструктор, который будет вызван, если elision не выполняется, и выбранный конструктор
должен быть доступен, даже если вызов отменен.