Итак, как в наши дни пишутся базовые классы на C++11?

Обновление: я использую MSVC10, что не дает мне семантики перемещения по умолчанию

Допустим, я хочу создать обычный класс с парой участников, не являющихся членами модуля;

class Foo {
NonPodTypeA a_;
NonPodTypeB b_;
}

Как обычно, я реализую конструктор копирования и оператор присваивания, в котором я использую конструктор копирования:

Foo(const Foo& other) : a_(other.a_), b_(other.b_) {}
Foo& operator=(const Foo& other) { 
  Foo constructed(other);
  *this = std::move(constructed);
  return *this;
}

Затем я реализую конструктор перемещения и назначение перемещения, в котором используется std::swap вместо std::move для всех членов, поскольку они могли быть написаны до того, как стала доступна семантика перемещения, поскольку семантика перемещения реализована, я могу опустить реализацию функция-член подкачки:

Foo(Foo&& other) {
  ::std::swap(a_, other._a);
  ::std::swap(b_, other._b);
}
Foo& operator=(Foo&& other) { 
  ::std::swap(a_, other._a);
  ::std::swap(b_, other._b);
  return *this;
}

И вот мой вопрос; можно ли здесь сделать что-то более общее, предполагая, что я ничего не знаю об участниках?

Например, конструктор перемещения не совместим с членами, объявленными const, но если я реализую конструктор перемещения как Foo(Foo&& other) : a_(std::move(other.a_)), b_(std::move(other.b_)){}, я не могу быть уверен, что классы без семантики перемещения не будут скопированы? Могу ли я каким-то умным образом использовать конструктор перемещения в назначении перемещения?


person Viktor Sehr    schedule 11.03.2012    source источник
comment
Как обычно, вы ничего не реализуете. Пусть a_ и b_ позаботятся о себе.   -  person Benjamin Lindley    schedule 12.03.2012
comment
В этом больше неправильного, чем правильного. Среди прочего, не следует полностью квалифицировать std::swap.   -  person ildjarn    schedule 12.03.2012
comment
ADL следует использовать для вызова swap, а не явной квалификации (если только эта квалификация не является boost::swap, которая будет использовать ADL внутри).   -  person ildjarn    schedule 12.03.2012
comment
ildjarn: Я до сих пор не понимаю, если в классе реализована семантика перемещения, то std::swap будет ее использовать (по крайней мере, в MSVC10)   -  person Viktor Sehr    schedule 12.03.2012
comment
И если типы данных имеют пользовательский обмен, вы не хотите вызывать std::swap, вы хотите вызвать пользовательский.   -  person ildjarn    schedule 12.03.2012
comment
ildjarn: Когда типы данных имеют функцию-член подкачки, я предполагаю, что std::swap перегружен для этого типа.   -  person Viktor Sehr    schedule 12.03.2012
comment
@ViktorSehr: вам не разрешено добавлять перегрузки к namespace std. Вот почему вы хотите выбрать swap из пространства имен ADL.   -  person MSalters    schedule 12.03.2012


Ответы (2)


Эм, ничего не делайте. Все это создается автоматически1. Единственный раз, когда вам нужно написать их вручную, это когда класс обрабатывает ресурсы (и тогда вам нужно следовать Правило трех). Точно так же было и раньше. Единственная разница заключается в том, что после того, как вы рассмотрели правило трех, вы можете захотеть реализовать элементы перемещения либо по семантическим причинам (т.е. создание объектов, предназначенных только для перемещения), либо по соображениям производительности (перемещения обычно выполняются быстрее, чем копии). .


1. MSVC 10 не создает конструкторы перемещения автоматически. В этом случае вы можете сами написать элементы перемещения :(

person R. Martinho Fernandes    schedule 11.03.2012
comment
MSVC 10 не создает конструкторы перемещения автоматически, но это отсутствующая функция, которая будет добавлена ​​в MSVC 11. Это не мое понимание. У вас есть ссылка, подтверждающая это? - person ildjarn; 12.03.2012
comment
Это не будет добавлено в VC11. Думайте больше в духе VC 11.1. - person Nicol Bolas; 12.03.2012
comment
@ildjarn ой, я запутался. Кажется, в VC11 его все-таки нет :( блоги. msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx - person R. Martinho Fernandes; 12.03.2012

Учитывая ограничения MSVC10 и MSVC11, заключающиеся в том, что вам нужно писать свои собственные конструкторы перемещения/операторы присваивания перемещения, у меня есть следующее. Я взял за основу это видео Stephan T. Lavavej.

http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-9-of-n

class Foo 
{
public:

    //Note: don't pass param by reference. Unified assignment operator
    Foo& operator=(Foo other)
    {
        other.swap(*this);
        return *this;
    }

    Foo(Foo&& other)
      : a_(std::move(other.a_),
        b_(std::move(other.b_){}

    Foo(Foo& other)
      : a_(other.a_),
        b_(other.b_){}

private:
    void swap(Foo& other)
    {
        using std::swap;
        swap(a_, other.a_);
        swap(b_, other.b_);
    }

private:
    NonPodTypeA a_;
    NonPodTypeB b_;
};
person Alastair Taylor    schedule 12.03.2012