Этот пост немного бессвязный, поэтому, прежде чем я перейду к нему, я хочу прояснить, о чем я спрашиваю :Добавили ли вы сеттеры с поддержкой перемещения -в свой код и считаете ли вы, что это стоит затраченных усилий? И насколько поведение, которое я обнаружил, может быть специфичным для компилятора -?
Здесь я смотрю на то, стоит ли добавлять функцию установки с поддержкой перемещения -в тех случаях, когда я устанавливаю свойство сложного типа. Здесь у меня включено перемещение -Bar
и Foo
, у которых есть свойство Bar
, которое можно установить.
class Bar {
public:
Bar() : _array(1000) {}
Bar(Bar const & other) : _array(other._array) {}
Bar(Bar && other) : _array(std::move(other._array)) {}
Bar & operator=(Bar const & other) {
_array = other._array;
return *this;
}
Bar & operator=(Bar && other) {
_array = std::move(other._array);
return *this;
}
private:
vector<string> _array;
};
class Foo {
public:
void SetBarByCopy(Bar value) {
_bar = value;
}
void SetBarByMovedCopy(Bar value) {
_bar = std::move(value);
}
void SetBarByConstRef(Bar const & value) {
_bar = value;
}
void SetBarByMove(Bar && value) {
_bar = std::move(value);
}
private:
Bar _bar;
};
Вообще говоря, в прошлом я использовал const -ref для функций установки для не встроенных -типов. Варианты, которые я рассматривал, заключались в том, чтобы пройти по значению -, а затем перейти(SetByMovedCopy
), передайте const -ref, затем скопируйте(SetByConstRef
)и, наконец, принять значение r --ref, затем переместить(SetByMove
). В качестве основы я также включил передачу -по значению -, а затем копирование (SetByCopy
).. ПСВ,компилятор жаловался на двусмысленность при включении перегрузок pass -by -value и r -value -ref.
В экспериментах с компилятором VS2010 я обнаружил вот что:
Foo foo;
Bar bar_one;
foo.SetByCopy(bar_one);
// Bar::copy ctor called (to construct "value" from bar_one)
// Foo::SetByCopy entered
// Bar::copy operator= called (to copy "value" to _bar)
// Foo::SetByCopy exiting
// Bar::dtor called (on "value")
value
является копией -, созданной из bar_one
, тогда value
копируется в bar
. value
уничтожается и берет на себя все затраты на уничтожение всего объекта. Выполняются 2 операции копирования.
foo.SetByMovedCopy(bar_one);
// Bar::copy ctor called (to construct "value" from bar_one)
// Foo::SetByCopy entered
// Bar::move operator= called (to move "value" into _bar)
// Foo::SetByCopy exiting
// Bar::dtor called (to destruct the moved "value")
value
это копия -, построенная из bar_one
, затем value
перемещается в _bar
, затем выпотрошенный value
уничтожается после выхода из функции, предположительно с меньшими затратами. 1 копирование и 1 перемещение.
foo.SetByConstRef(bar_one);
// Foo::SetByConstRef entered
// Bar::copy operator= called (to copy bar_one into _bar)
// Foo::SetByConstRef exiting
bar_one
копируется непосредственно в _bar
. 1 операция копирования.
foo.SetByMove(std::move(bar_one))
// Foo::SetByMove entered
// Bar::move operator= called (to move "value" into _bar)
// Foo::SetByMove exited
bar_one
перемещается непосредственно в _bar
. 1 операция перемещения.
Таким образом, версии const -ref и move в данном случае наиболее эффективны. Теперь, ближе к делу, то, что я хочу сделать, это что-то вроде этого:
void SetBar(Bar const & value) { _bar = value; }
void SetBar(Bar && value) { _bar = std::move(value); }
Я обнаружил, что здесь происходит следующее: если вы вызываете Foo::SetBar
, компилятор выбирает функцию в зависимости от того, передаете ли вы значение l -или значение r -. Вы можете форсировать проблему, позвонив std::move
как таковой:
foo.SetBar(bar_one); // Const-ref version called
foo.SetBar(Bar()); // Move version called
foo.SetBar(std::move(bar_one)); // Move version called
Я содрогаюсь при мысли о добавлении всех этих сеттеров перемещения, но я думаю, что это может привести к довольно значительному приросту производительности в случаях, когда временное значение передается функции SetBar
, и в будущем я могу получить еще больше, применив std::move
, где подходящее.