Что, с точки зрения стандарта С ++, ожидаемый (если таковые имеются) выход следующей программы:Какова ценность is_nothrow_copy_assignable для класса с металическим конструктором копирования и присваиванием копии noexcept by-value?
#include <iostream>
#include <iomanip>
#include <type_traits>
class A {
public:
A() = default;
~A() = default;
A(A const& other) {}
A(A&& other) noexcept {}
A& operator=(A other) noexcept { return *this; }
};
int main() {
std::cout << std::boolalpha
<< std::is_nothrow_copy_assignable<A>::value << "\n"
<< std::is_nothrow_move_assignable<A>::value << "\n";
}
Другими словами, это оценка значений признаков, типа смотрите в декларации из оператор присваивания только, что noexcept, и делает это таким образом, выход
true
true
Или это учитывать контекст вызова (a
, b
являются экземплярами A
)
a = b; // may throw, implicitly calls copy c'tor
a = std::move(b); // noexcept, implicitly calls move c'tor
и делает это выход
false
true
Практические попытки
Запуск кода с Visual Studio 2015, Update 3 дает
true
true
, тогда как GCC 6.1 дает
false
true
Кто такой?
фон
Ситуация, как это происходит, когда у нас есть управляющий ресурсом класса с конструктором метания копий (с выделением ресурсов может произойти сбой), шаг конструктор noexcept, назначение метания копий и назначение noexcept перемещения ,
Предположив, что и копирование и перемещение назначения может быть эффективно реализован с точки зрения обмена ИПЧМ:
A& operator=(A const& other) {
A(other).swap(*this); // calls the copy c'tor, may throw
return *this;
}
A& operator=(A&& other) noexcept {
A(std::move(other)).swap(*this); // calls noexcept move c'tor
return *this;
}
Тогда мы могли бы рассмотреть конденсацию как в одной по значению присвоения копии
A& operator=(A other) noexcept {
other.swap(*this);
return *this;
}
Однако мы можем только безопасно это сделать, если std::is_nothrow_copy_assignable<A>
и std::is_nothrow_move_assignable<A>
содержат правильные значения (соответственно false и true). В противном случае код, основанный на этих типах, будет вести себя плохо, и наше одиночное присваивание по значению будет не быть правильной заменой для двух отдельных операторов присваивания.
Для 'vector' вам нужно' is_nothrow_move_assignable' быть правильным, но не обязательно 'is_nothrow_copy_assignable'. Также нет необходимости использовать 'boolalpha' дважды. –
Спасибо за замечания. Я соответствующим образом отредактировал вопрос. Конечно, '' s_nothrow_copy_assignable' должен по-прежнему вести себя корректно, даже если 'std :: vector' его не требует. – jbab
На самом деле, я смутился. 'vector' требует, чтобы' is_nothrow_move_constructible' был правильным, чтобы получить полную эффективность при перераспределении. Я не могу вспомнить, если что-то в нем действительно хочет 'is_nothrow_move_assignable'. Но да, независимо от того, заботится ли об этом «вектор», черты должны вести себя правильно. –