Q1: что делать с Foo::at( int ) const
, чтобы вы могли:
myfoo.at(i)->doSomething(param1, param2, ...);
без передачи права собственности на vector<unique_ptr<Shape<T>>>
.
A1: Foo::at( int ) const
должен вернутьconst std::unique_ptr<Shape<T> >&
:
template < typename T >
const std::unique_ptr<Shape<T> >&
Foo<T>::at( int index ) const
{
return m_Bank[index];
}
Теперь вы можете разыменовать const unique_ptr
и вызывать любого члена Shape
, которого они хотят (const или non-const).Если они случайно попытаются скопировать unique_ptr
(что приведет к передаче права собственности из Foo
), они получат ошибку времени компиляции.
Это решение лучше, чем возвращение неконстантной ссылки на unique_ptr
так как он ловит случайные переходы собственности из Foo
.Однако, если вы хотите разрешить передачу прав собственности из Foo
через at
, тогда неконстантная ссылка будет более уместной.
Q2: Кроме того, недавно я нашел в Интернете пример того, какперегрузить оператор присваивания, используя std :: move.Я обычно следую идиоме Copy-Swap.Какой из этих двух способов перегрузки упомянутого оператора имеет смысл для моего случая?
A2: Я не уверен, что делает ~Foo()
.Если он ничего не делает, вы можете удалить его, а затем (при условии полного соответствия C ++ 11) вы автоматически получите правильный и оптимальный конструктор перемещения и оператор присваивания перемещения (и правильную семантику удаленной копии).
Если вы не можете удалить ~Foo()
(потому что он делает что-то важное), или если ваш компилятор еще не реализует автоматическую генерацию перемещения, вы можете указать их явно, как вы это сделали в своем вопросе.
Ваш конструктор перемещения находится на месте: Переместите конструкцию члена.
Ваше назначение перемещения должно быть аналогичным (и это то, что будет автоматически генерироваться, если ~Foo()
неявно): Переместить назначить члена:
template < typename T >
Foo<T> & Foo<T>::operator =( Foo<T> && bank )
{
m_Bank = std::move(bank.m_Bank);
return (*this);
}
Ваш Foo
дизайн также может быть Swappable
, и это всегда хорошо:
friend void swap(Foo& x, Foo& y) {x.m_Bank.swap(y.m_Bank);}
Без этого явного swap
ваш Foo
все еще Swappable
, используя Foo
конструктор перемещения и назначение перемещения.Однако этот явный swap
примерно в два раза быстрее неявного.
Приведенный выше совет направлен на получение максимальной производительности из Foo
.При желании вы можете использовать идиому Copy-Swap в своем задании на перемещение.Это будет правильно и немного медленнее.Хотя, если вы действительно будете осторожны, вы не получите бесконечную рекурсию с swap
, вызывающим перемещение, и перемещением, вызывающим swap
!:-) Действительно, эта ошибка - еще одна причина для чистого (и оптимального) разделения swap
и перемещения назначения.
Обновление
Предполагается, что Shape
выглядит this , вот один из способов кодирования конструктора перемещения, назначения перемещения, конструктора копирования и операторов копирования для Foo
, при условии, что Foo
имеет один элемент данных:
std::vector< std::unique_ptr< Shape > > m_Bank;
...
Foo::Foo(Foo&& other)
: m_Bank(std::move(other.m_Bank))
{
}
Foo::Foo(const Foo& other)
{
for (const auto& p: other.m_Bank)
m_Bank.push_back(std::unique_ptr< Shape >(p ? p->clone() : nullptr));
}
Foo&
Foo::operator=(Foo&& other)
{
m_Bank = std::move(other.m_Bank);
return (*this);
}
Foo&
Foo::operator=(const Foo& other)
{
if (this != &other)
{
m_Bank.clear();
for (const auto& p: other.m_Bank)
m_Bank.push_back(std::unique_ptr< Shape >(p ? p->clone() : nullptr));
}
return (*this);
}
Если ваш компилятор поддерживает заданные по умолчанию элементы перемещения, то же самое можно сделать с помощью:
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
для конструктора перемещения и оператора присваивания перемещения.
Вышеуказанное гарантирует, что каждый Shape
всегда принадлежит только одному интеллектуальному указателю / вектору / Foo.Если вы предпочитаете, чтобы владение несколькими Foo
s принадлежало Shape
s, тогда вы можете иметь в качестве члена данных:
std::vector< std::shared_ptr< Shape > > m_Bank;
И вы можете по умолчанию использовать конструктор перемещения, назначение перемещения, конструктор копированияи скопируйте назначение.