Почему удаление конструктора перемещения вызывает ошибку компиляции? - PullRequest
15 голосов
/ 10 мая 2019

Следующий код работает нормально:

#include <iostream>
using namespace std;
struct oops
{
        ~oops()
        {
                cout << " oops! " << endl;
        }
};

struct sample
{
        oops* x = nullptr;
        sample(oops* p) : x(p)
        {
                cout << "sample: " << p << endl;
        }
        ~sample()
        {
                delete x;
                cout << "destroy sample " << endl;
        }
        sample(const sample&)
        {
                cout << "copy sample " << endl;
        }
        sample(sample&&)
        {
                cout << "move sample " << endl;
        }
};

int main()
{
        sample s = new oops;
        return 0;
}

Результат:

sample: 0x1470c20
 oops!
destroy sample

Это ясно показывает, что не был вызван ни конструктор перемещения, ни копирования.Когда эти конструкторы удаляются,

sample(const sample&) = delete;
sample(sample&&) = delete;

gcc выдает ошибку компиляции:

bpp.cpp: In function ‘int main()’:
bpp.cpp:29:17: error: use of deleted function ‘sample::sample(sample&&)’
  sample s = new oops;
                 ^
bpp.cpp:24:2: note: declared here
  sample(sample&&) = delete;
  ^
bpp.cpp:14:2: note:   after user-defined conversion: sample::sample(oops*)
  sample(oops* p) : x(p)
  ^

Имеет ли это какое-либо отношение к -fno-elide-constructors?Как я могу скомпилировать его без определения этих конструкторов или использования явного конструктора?

Редактировать: Моя версия GCC - 5.4.0.Команда:

g++ bpp.cpp -std=c++17

Ответы [ 2 ]

17 голосов
/ 10 мая 2019
sample s = new oops;

Это форма копирования инициализации .Чтобы компилятор разрешил его до C ++ 17, должен существовать конструктор копирования или перемещения.Тем не менее, компилятор может отказаться от своего вызова из-за оптимизации (с GCC и -fno-elide-constructors, вызывается конструктор перемещения).

Начиная с C ++ 17, ни один из этих конструкторов не требуется: https://wandbox.org/permlink/3V8glnpqF5QxljJl.


Как я могу скомпилировать его без определения этих конструкторов или использования явного конструктора?

Очень просто, избежать скопировать инициализацию и использовать прямая инициализация вместо:

sample s { new oops };

Или используйте C ++ 17.

6 голосов
/ 10 мая 2019

Почему это не скомпилируется?

Эта строка кода:

sample s = new oops;

эквивалентно написанию:

sample s = sample(new oops);

В C ++ 11 и C ++ 14 это неявно вызывает конструктор перемещения (или конструктор копирования, если конструктор перемещения недоступен). Поскольку компиляторам разрешено исключать копии и перемещения, фактическое перемещение исключается и ничего не отображается при вызове конструктора перемещения. Несмотря на то, что фактическое перемещение не выполняется, программам не разрешается ссылаться на удаленные функции даже неявно , поэтому есть ошибка компилятора.

Это можно исправить, изменив инициализацию на

sample s { new oops };

или

sample s ( new oops );

или, если вы действительно хотите использовать =, вы можете воспользоваться временным продлением жизни для записи

// s won't get destroyed until the end of the scope
// it's safe to use s after this statement
sample&& s = new oops;

Что меняет C ++ 17?

C ++ 17 внес некоторые изменения в набор объектов категорий значений. В C ++ 17 sample(new oops) становится prvalue, а стандарт c ++ 17 требует, чтобы компиляторы требовали получения prvalue на месте без копирования или перемещения их. Это делается с помощью комбинации темной магии и колдовства.

Это означает, что sample s = new oops; законно в c ++ 17.

Почему при добавлении -std=c++17?

он все еще не компилируется

Этот код должен компилироваться в C ++ 17 , и ошибка, которую вы получаете, происходит из-за того, что gcc 6.3 и более ранние версии не реализуют эту часть стандарта c ++ 17. Эта проблема была исправлена ​​в gcc 7.1 , и код будет скомпилирован должным образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...