Элемент unique_ptr, личный конструктор копирования и конструктор перемещения

Учитывая базовый класс для нескольких производных классов, цель состояла в том, чтобы создать класс-оболочку, который позволял бы контейнеру STL видеть объекты с базовым интерфейсом, хотя на самом деле различные производные классы могут фактически добавляться в контейнер. (См. Получение данных из разнородного std:: list).

После некоторой обработки я придумал новый производный класс, который был оберткой вокруг unique_ptr в базовый класс. Тем не менее, конструктор перемещения меня запутал.

class Base {
    friend class BaseWrapper;
    virtual Base * clone () const = 0;
public:
    virtual ~Base () {}
    //... public interface
};

class Derived : public Base {
    //... specific members for derived class
    Base * clone () const { return new Derived(*this); }
public:
    //... implement public interface
};

class BaseWrapper : public Base {
    std::unique_ptr<Base> ptr_;
    Base * clone () const { return ptr_->clone(); }
public:
    BaseWrapper (const Base &b) : ptr_(b.clone()) {}
    //... implement public interface by forwarding to ptr_
};

typedef std::list<BaseWrapper> BaseList;

int main () {
    BaseList l;
    l.push_back(Derived());
}

Это не компилируется с g ++ 4.7.2.

Теперь для того, чтобы использовать BaseWrapperЯ могу реализовать публичный конструктор перемещения следующим образом:

    BaseWrapper (BaseWrapper &&bw) { ptr_.swap(bw.ptr_); }

И это прекрасно работает. Но если я сделаю это приватным, он не скомпилируется.

Тем не менее, я обнаружил, что вместо вышесказанного я могу вместо этого определить частный конструктор "копирования" (конечно, также делает его общедоступным):

    BaseWrapper (BaseWrapper &bw) { ptr_.swap(bw.ptr_); }

Может ли кто-нибудь сказать мне, если это должно сработать, и почему или почему нет? Если он должен работать, почему я не могу сделать конструктор перемещения закрытым?

Вы можете перейти по этой ссылке на игрушечную программу, иллюстрирующую вышеупомянутое более полным способом.

1 ответ

Решение

[убрал ошибочную диагностику]

Это на самом деле компилируется на GCC 4.8. Похоже гкк 4.7 берет BaseWrapper (const Base &) как конструктор копирования (который на самом деле не является), и неявно удаляет конструктор перемещения (что было бы ожидаемым поведением, если бы это был действительно конструктор копирования).

Другие вопросы по тегам