C++重抛异常场景下stdout与stderr打印顺序异常,是否为预期行为?
C++重抛异常场景下stdout与stderr打印顺序异常,是否为预期行为?
嘿,这个问题我当初刚学异常处理的时候也踩过坑,一开始看着乱掉的打印顺序差点以为自己代码写错了,其实这真的是预期行为,咱们来掰扯清楚为啥会这样~
核心原因其实和异常重抛关系不大,问题出在C++里的两个标准输出流:stdout(对应cout)和stderr(对应cerr)的缓冲策略不一样:
stdout是带缓冲的:用cout打印的内容不会立刻显示在终端,而是先存在内存缓冲区里,只有当缓冲区被填满、程序正常结束,或者你手动调用std::flush/用std::endl(endl会自动触发flush)的时候,才会把缓冲区里的内容输出到终端。stderr是无缓冲的:用cerr打印的内容会直接输出到终端,不会在缓冲区里停留。
举个贴合你场景的代码例子(补全了你没写完的部分):
#include <iostream> #include <stdexcept> void foo4(const int a) { std::cout << "foo4 start\n"; // 这句会存在stdout缓冲区 if (a == 0) { throw std::runtime_error("invalid argument"); } std::cout << "foo4 executed successfully\n"; } void foo3(int a) { try { foo4(a); } catch (...) { std::cerr << "Caught in foo3, rethrowing...\n"; // 直接输出到终端 throw; } } int main() { try { foo3(0); } catch (const std::exception& e) { std::cerr << "Caught in main: " << e.what() << "\n"; // 直接输出到终端 } return 0; }
当你传入a=0时,foo4里先执行了cout,但内容还在缓冲区没输出,紧接着抛出异常。然后foo3和main里的cerr会直接打印内容,等程序结束的时候,才会把stdout缓冲区里的内容刷出来。所以终端的输出顺序会是:
Caught in foo3, rethrowing... Caught in main: invalid argument foo4 start
看起来顺序完全反了,但这真的是正常的,不是代码逻辑或者异常重抛的问题。如果想要让cout的内容及时输出,和cerr的顺序一致,你可以在cout后面手动加std::flush,或者用std::endl代替\n,比如把std::cout << "foo4 start\n";改成std::cout << "foo4 start" << std::endl;,这样就能立刻把缓冲区的内容刷到终端,顺序就正常了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

