Предотвращение вызова конструктора копирования при возврате созданного объекта по значению в C ++ 11 - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть класс без конструктора копирования, который я все еще хочу вернуть по значению.Следующие MCVE компилируются в C ++ 17:

class Cls {
    public:
    Cls(int x) {}
    Cls(const Cls& c) = delete;
};

Cls f(int x) {
    return Cls(x);
}

int main() {
    f(0);
}

, но не в C ++ 11:

$ g++ prog.cc -Wall -Wextra -std=c++11
prog.cc: In function 'Cls f(int)':
prog.cc:9:17: error: use of deleted function 'Cls::Cls(const Cls&)'
    9 |     return Cls(x);
      |                 ^
prog.cc:5:5: note: declared here
    5 |     Cls(const Cls& c) = delete;
      |     ^~~

Насколько я понимаю, причина в том, что компилятор разрешен не , чтобы оптимизировать копию, даже если это должно быть тривиально в этом случае.

Я надеялся, что return std::move(Cls(x)); сработает и избежит конструктора копирования, но он выдаст ту же ошибку.

Можно ли исправить проблему без определения конструктора копирования (или оператора присвоения)?

Я просмотрел похожие вопросы, но не смог найти дубликат.

Ответы [ 3 ]

0 голосов
/ 01 февраля 2019

Насколько я понимаю, причина в том, что компилятору разрешено не оптимизировать копию, даже если в этом случае это должно быть тривиально.

Это верно.

Я надеялся вернуть std :: move (Cls (x));будет работать и избежать конструктора копирования, но выдает ту же ошибку.

Это не решение.std::move(Cls(x)); ничего не сделает, так как Cls(x) уже дает prvalue .Преобразование возвращаемых значений в значения r следует выполнять в редких случаях, например, при возврате параметра функции.Кроме того, Cls rvalue может использоваться без копирования, только если вы можете переместить-создать другой экземпляр из этого rvalue, чего нет в вашем исходном фрагменте.

Могу ли я решить проблему безопределить конструктор копирования (или оператор присваивания)?

Вместо этого вы можете определить конструктор перемещения, как предложено в ответе @ Matthieur Brucher .Это позволяет возвращать временный объект типа Cls, но при этом запрещать копирование.Вы называете это типом «только для перемещения», и один из наиболее известных стандартных типов, «только для перемещения», - это std::unique_ptr.

В качестве последнего примечания, я думаю, что хорошей практикой является следовать C.21 , что предполагает обработку перемещения / конструирования / присваивания и не полагаться на неявное удаление этих специальных функций-членов.

0 голосов
/ 01 февраля 2019

Можно ли исправить проблему, не задавая конструктор копирования (или оператор назначения)?

В вашем случае есть 2 варианта:

  • Определить конструктор перемещения:

    Cls(Cls&& c) = default;
    
  • Использовать copy-list-initialization , который позволяет не вызывать конструктор копирования / перемещения, для этого требуется неявныйКонструктор:

    Cls f(int x) {
        return {x};
    }
    

    Демонстрация

В C ++ 17 у вас есть "гарантия" копирования-разрешения (или "передача не материализованного значения""), так что return Cls(x); будет в порядке.

0 голосов
/ 01 февраля 2019

Вместо этого реализуйте конструктор перемещения.

В C ++ 17 компилятор должен выполнить copy elision и может не нуждаться в копировании или перемещении объекта.Но для C ++ 11 у вас нет этой возможности, но у вас есть ход для вашего дела:

Cls(Cls&& c) = default;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...