Подтвердить что ты не робот

Вызов неявно удаленной копии в LLVM

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

call to implicitly deleted copy constructor of 'Uni'

Когда я пишу свой собственный конструктор копий для Uni, все работает нормально. (Он комментируется в коде, приведенном для справки)

Любые мысли очень ценятся.

Наконец, я запускаю это на Mac, Xcode с компилятором LLVM.

большое спасибо...

#include <iostream>

class A
{
public:
    A(int i) :num{i}
    {
        std::clog<< "ctor  A() num = " << num << "\n";

    }
    A( A const &aRef)
    :num{aRef.num}
    {
        std::clog << " copy ctor A( A const &aRef) num = " << num << "\n";
    }

    int value()
    {
        return num;
    }

private:
    int num;

};
class Uni
{

public:
    Uni(A* aptr) : up{aptr}
    {
        std::clog << " ctor Uni value = " << up.get()->value() << "\n";
    }
    /*Uni(Uni const &uRef)
    {
        std::clog << " copy ctor Uni copying obj pointed by unique_ptr\n";
        up.reset(uRef.up.get() ? new A{*uRef.up.get()} : nullptr);
    }*/
private:
    std::unique_ptr<A> up;

};

int main(int argc, const char * argv[])
{
    Uni one{new A{10}};
    Uni two{one}; //default copy ctor is implicitly deleted. why ?
}
4b9b3361

Ответ 1

С++ 11 правил автоматической генерации специальных членов не так просты, как вы их разместили. Самое важное отличие состоит в том, что в некоторых случаях член объявляется неявно, но определяется как удаленный. Что происходит в вашем случае.

С++ 11, [class.copy] §11:

По умолчанию конструктор копирования/перемещения для класса X определяется как удаленный (8.4.3), если X имеет:

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

(Акцент мой)


В общем случае правилами для автогенерируемых членов класса являются:

  • Если класс не имеет конструкторов, предоставляемых пользователем, объявляется конструктор по умолчанию.

  • Если класс не имеет предоставленного пользователем конструктора копирования, объявляется один из них.

  • Если класс не имеет {созданный пользователем экземпляр или механизм перемещения, предоставленный пользователем экземпляр или оператор назначения перемещения, предоставленный пользователем деструктор}, будет объявлен конструктор перемещения (но см. ниже (*)).

  • Если класс не имеет предоставленного пользователем оператора назначения копирования, объявляется один из них.

  • Если класс не имеет {созданного пользователем экземпляра копирования или перемещения, предоставленного пользователем экземпляра копирования или перемещения оператора назначения, предоставленного пользователем деструктора}, будет объявлен оператор назначения перемещения (но см. (*) ниже).

  • Если класс не имеет деструктора, предоставленного пользователем, он объявляется.

Любой автоматически объявленный член может быть определен как дефолт (выполняющий материал по умолчанию) или определенный как удаленный (если вы попытаетесь его использовать, вы получите сообщение об ошибке). Эмпирическое правило: "Если версия по умолчанию имеет смысл, она будет определена как дефолт. В противном случае она будет определена как удаленная".

В этом контексте "имеет смысл" означает "не пытается вызвать удаленную, двусмысленную, недоступную или незаконную функцию". Например, стандартный бит, который я цитировал в первой части этого ответа, перечисляет то, что не имеет смысла для конструкторов копирования.

Кроме того, автоматически объявленный конструктор копирования или оператор присваивания копии определяется как удаленный, если класс имеет предоставленный пользователем конструктор перемещения или оператор переадресации.

(*) Если автоматически объявленный конструктор перемещения или оператор назначения перемещения будет определен как удаленный, он не будет объявлен вообще. Это правило существует, так что попытка перемещения такого класса неявно возвращается к копированию, вместо того, чтобы генерировать ошибку.