Будьте очень осторожны в смысле назначения копирования / обмена. Это может быть неоптимальным, особенно когда применяется без тщательного анализа. Даже если вам нужна строгая безопасность исключений для оператора присваивания, эта функциональность может быть получена иным способом.
Для вашего примера я рекомендую:
struct my_type
{
my_type(std::string name_)
: name(std::move(name_))
{}
void swap(my_type &other)
{
name.swap(other.name);
}
private:
std::string name;
};
Это позволит вам неявно копировать и перемещать семантику, которая пересылает в std :: string для копирования и перемещения членов. И автор std :: string лучше всех знает, как выполнить эти операции.
Если ваш компилятор еще не поддерживает неявную генерацию перемещения, но поддерживает специальные члены по умолчанию, вы можете сделать это вместо этого:
struct my_type
{
my_type(std::string name_)
: name(std::move(name_))
{}
my_type(const mytype&) = default;
my_type& operator=(const mytype&) = default;
my_type(mytype&&) = default;
my_type& operator=(mytype&&) = default;
void swap(my_type &other)
{
name.swap(other.name);
}
private:
std::string name;
};
Вы также можете сделать это, если хотите просто открыто рассказать о своих специальных членах.
Если вы имеете дело с компилятором, который еще не поддерживает дефолтные специальные элементы (или неявные элементы перемещения), то вы можете явно указать, что компилятор должен в конечном итоге установить по умолчанию, когда он станет полностью совместимым с C ++ 11:
struct my_type
{
my_type(std::string name_)
: name(std::move(name_))
{}
my_type(const mytype& other)
: name(other.name) {}
my_type& operator=(const mytype& other)
{
name = other.name;
return *this;
}
my_type(mytype&& other)
: name(std::move(other.name)) {}
my_type& operator=(mytype&& other)
{
name = std::move(other.name);
return *this;
}
void swap(my_type &other)
{
name.swap(other.name);
}
private:
std::string name;
};
Если вам действительно нужна строгая безопасность исключений для назначения, разработайте его один раз и проясните его (отредактируйте, чтобы включить предложение Люка Дантона):
template <class C>
typename std::enable_if
<
std::is_nothrow_move_assignable<C>::value,
C&
>::type
strong_assign(C& c, C other)
{
c = std::move(other);
return c;
}
template <class C>
typename std::enable_if
<
!std::is_nothrow_move_assignable<C>::value,
C&
>::type
strong_assign(C& c, C other)
{
using std::swap;
static_assert(std::is_nothrow_swappable_v<C>, // C++17 only
"Not safe if you move other into this function");
swap(c, other);
return c;
}
Теперь ваши клиенты могут выбирать между эффективностью (мой тип :: оператор =) или строгой безопасностью исключений, используя strong_assign
.