std::is_nothrow_move_assignable 是编译期类型特征,用于判断类型是否支持不抛异常的移动赋值操作;它检查 t::operator=(t&&) 是否被声明或隐式生成为 noexcept,受成员/基类是否 noexcept 约束,且不接受引用或数组类型。

std::is_nothrow_move_assignable 是什么,能用来判断什么
std::is_nothrow_move_assignable 是一个类型特征(type trait),用于在编译期判断某个类型是否支持不抛异常的移动赋值操作。它不关心你有没有显式定义移动赋值运算符,只看实际调用 T::operator=(T&&) 是否被声明为 noexcept,或是否因隐式生成而满足 noexcept 条件。
典型误判场景:类里成员有非 noexcept 移动赋值的成员(比如 std::vector 默认是 noexcept,但自定义类型若没标 noexcept,就会拖累整个类)。
怎么写判断语句,常见写法和陷阱
直接用 std::is_nothrow_move_assignable_v<t></t>(C++17 起推荐)最简洁;C++11/14 用 std::is_nothrow_move_assignable<t>::value</t>。
- 必须传入完整类型名,不能传引用或 cv 限定符:
std::is_nothrow_move_assignable_v<foo></foo>返回false(即使Foo本身满足),因为引用类型没有移动赋值操作符 - 数组类型默认不满足:
std::is_nothrow_move_assignable_v<int></int>是false,C++ 不允许对数组对象做移动赋值 - 空基类优化不影响结果,但继承链中任一基类或成员的移动赋值不
noexcept,整个类就失败
示例:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
struct Good {
std::string s;
Good& operator=(Good&&) noexcept = default; // 编译器生成的,且 string::operator=(string&&) 是 noexcept
};
static_assert(std::is_nothrow_move_assignable_v<good>, "should be true");</good>
为什么明明写了 noexcept 却还是 false
最常见原因是:你声明了 operator=(T&&) 并加了 noexcept,但函数体里调用了可能抛异常的代码(比如手动调用 new、未标记 noexcept 的成员函数、或 throw 表达式),编译器会忽略你的 noexcept 声明并视为可能抛异常。
- 检查所有被调用的成员/基类移动赋值是否真的
noexcept:用static_assert分别验证它们 - 注意
std::move本身不抛异常,但后续调用的函数决定最终行为 - 模板类中依赖模板参数时,
noexcept可能变成noexcept(noexcept(...))形式,需确保推导正确
反例:
struct Bad {
std::vector<int> v;
Bad& operator=(Bad&& other) noexcept { // ❌ 这里写了 noexcept,但 vector::operator= 是 noexcept(true),所以其实 OK —— 但如果你换成自定义容器且其 operator= 没标 noexcept,就挂了
v = std::move(other.v);
return *this;
}
};</int>
和 std::is_move_assignable 的区别在哪
std::is_move_assignable 只判断“能否移动赋值”,不管是否 noexcept;而 std::is_nothrow_move_assignable 要求该操作必须是 noexcept。两者都依赖 SFINAE 或约束,但后者更严格。
- 如果类禁用了移动赋值(如
= delete),两个 trait 都返回false - 如果移动赋值存在但没标
noexcept(哪怕实际不抛),std::is_move_assignable_v<t></t>是true,std::is_nothrow_move_assignable_v<t></t>是false - 标准容器(如
std::vector、std::unique_ptr)通常对可移动类型提供noexcept移动赋值,但前提是其元素类型也满足
真正影响性能的点在于:某些标准库实现(如 std::vector::resize)在需要重新分配时,会优先选择 noexcept 移动而非拷贝,以避免异常安全问题——这时 std::is_nothrow_move_assignable 就不是玩具 trait,而是实打实的优化开关。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










