std::logic_error是用于主动抛出逻辑错误的异常基类,适用于违反前提条件的场景,如参数非法、下标越界等;不应用于运行期错误。

std::logic_error 是什么,什么时候该用它
它不是用来捕获错误的,而是用来主动抛出逻辑错误的——比如函数收到了明显违反前提条件的参数。C++ 标准库自己用它派生出 std::invalid_argument、std::out_of_range 等,你也可以继承它自定义逻辑异常类型。
常见误用:在运行时检测到文件打不开、网络超时、内存分配失败时抛 std::logic_error。这些属于运行期问题,该用 std::runtime_error 及其子类。
- 适合场景:
vector::at()下标越界、stoi()解析非数字字符串、自定义容器构造时传入负容量 - 不适合场景:磁盘满、系统调用失败、
new抛std::bad_alloc - 它的构造函数只接受
const char*或std::string,不带错误码或上下文堆栈
怎么正确抛出和捕获 std::logic_error
直接抛就行,但要注意消息内容要能定位问题;捕获时别只抓 std::exception 就完事——你会漏掉类型信息,失去区分逻辑错误和运行错误的能力。
void check_age(int age) {
if (age < 0 || age > 150) {
throw std::logic_error("age must be between 0 and 150, got: " + std::to_string(age));
}
}
- 抛出前拼接具体值(如上例),比只写 "invalid age" 更容易调试
- 捕获推荐按需分层:
catch (const std::out_of_range& e)→catch (const std::logic_error& e)→catch (const std::exception& e) - 不要用
catch (...)吞掉std::logic_error后不处理——这会让本该暴露的编程错误静默失败
std::logic_error 的子类有哪些,怎么选
标准里明确定义了 5 个直接子类,各自语义明确,别图省事全用 std::logic_error 本身。
立即学习“C++免费学习笔记(深入)”;
-
std::invalid_argument:参数值非法(如sqrt(-1.0)) -
std::domain_error:数学定义域违规(如acos(2.0)) -
std::length_error:对象长度超限(如std::string构造时指定过大 size) -
std::out_of_range:访问越界(vector::at()、string::at()) -
std::future_error:仅用于std::future相关状态异常,和其他逻辑错误语义不同
选哪个的关键是看“错在哪一层”:是用户传参错了(invalid_argument),还是你内部检查发现数据结构约束被破坏(out_of_range)?混用会让调用方难判断是否该重试或改输入。
自定义 logic_error 子类要注意什么
可以继承 std::logic_error,但别试图重写 what() 去加堆栈或自动补上下文——标准异常要求 what() 返回指向静态存储期字符串的指针,局部 std::string 会导致悬垂指针。
class invalid_config : public std::logic_error {
public:
explicit invalid_config(const std::string& msg)
: std::logic_error("config error: " + msg) {} // OK:基类 string 成员持有副本
};
- 构造函数里拼接消息必须交给基类
std::logic_error的std::string成员管理,别存裸指针 - 别在子类里加虚函数或额外成员变量——异常对象可能被复制多次,增加开销且无必要
- 如果需要携带错误码或位置信息(如文件行号),建议用独立的错误结构体,而不是塞进异常类
最常被忽略的一点:std::logic_error 和所有标准异常一样,析构函数是 noexcept 的。如果你在自定义子类的析构里做了可能抛异常的操作,编译器不会报错,但程序会在异常传播途中直接 terminate。











