提问人:digito_evo 提问时间:5/17/2023 最后编辑:user229044digito_evo 更新时间:5/19/2023 访问量:433
C++23 'print' 是否检查写入是否成功进入流?
Does C++23 `print` check to see if the write successfully made it into the stream?
问:
我想知道标准委员会是否已经修复了臭名昭著的 Hello, world! 错误。我主要谈论的是新的<print>
库(尚未在任何编译器中提供)。
{fmt} 库(启发了标准库)尚未修复此问题。显然,它在输出到(从 v9.1.0 开始)时不会抛出任何异常。因此,使用 C I/O 函数(例如用于错误处理)仍然是一回事。/dev/full
std::fflush
下面的程序注意到错误并返回失败代码(因此没有错误):
#include <exception>
#include <cstdio>
#include <cstdlib>
#include <fmt/core.h>
int main()
{
fmt::println( stdout, "Hello, world!" );
if ( std::fflush( stdout ) != 0 || std::ferror( stdout ) != 0 ) [[unlikely]]
{
return EXIT_FAILURE;
}
}
但这在 C++23 中可能吗?
#include <print>
#include <exception>
#include <cstdio>
#include <cstdlib>
int main()
{
try
{
std::println( stdout, "Hello, world!" );
}
catch ( const std::exception& ex )
{
return EXIT_FAILURE;
}
}
对于那些不知道“Hello World”错误的人,下面的程序(在 Rust 中)会崩溃并输出一条有用的错误消息:
fn main()
{
println!( "Hello, world!" );
}
./main > /dev/full
thread 'main' panicked at 'failed printing to stdout: No space left on device (os error 28)', library/std/src/io/stdio.rs:1008:9
相反,C++标准以及其他一些语言(C、Ruby、Java、Node.js、Haskell 等)默认情况下不会报告任何故障,即使在程序关闭时,程序关闭文件流时也是如此。另一方面,其他一些(Python3、Bash、Rust、C# 等)确实报告了错误。iostreams
答:
std::p rintln
函数的文档表明,如果它无法写入流,它将抛出 (以及其他失败的其他异常)。当然,成功写入流,失败通常发生在流实际写入文件系统时。std::system_error
std::println
在 C++ 环境中,如果您需要保证数据确实命中磁盘,您将在某些时候需要使用类似的东西并检查是否没有发生错误。您可以争论这是否方便,但这是从逻辑得出的,如果您不需要该功能,则不应有任何开销。这是一个功能,而不是一个错误。std::flush
如果需要此保证,请编写一个使用 RAII 技术的小包装器,以便在出现错误时抛出异常。这里有一个很好的讨论,关于析构函数中的释放语义与提交语义,以及何时加入析构函数是一个好主意。
示例代码
#include <iostream>
struct SafeFile {
SafeFile(const std::string& filename)
: fp_(fopen(filename.c_str(), "w"))
, nuncaught_(std::uncaught_exceptions()) {
if (fp_ == nullptr)
throw std::runtime_error("Failed to open file");
}
~SafeFile() noexcept(false) {
fflush(fp_);
if (ferror(fp_) and nuncaught_ == std::uncaught_exceptions()) {
fclose(fp_);
throw std::runtime_error("Failed to flush data");
}
fclose(fp_);
}
auto operator*() {
return fp_;
}
FILE *fp_{nullptr};
int nuncaught_{};
};
int main()
{
try {
SafeFile fp("/dev/urandom");
fprintf(*fp, "Hello, world!");
}
catch ( const std::exception& ex )
{
std::cout << "Caught the exception" << std::endl;
return EXIT_FAILURE;
}
}
输出
Caught the exception
评论
print
print
print
评论