有一个 C++ 代码,其中积极使用返回错误代码的 POSIX 调用。如果这样的调用返回错误,那么我会读取 errno 并抛出适当的异常throw std::system_error( errno, std::system_category(), "Сообщение об ошибе" );。对于每个这样的调用,我们都必须保存值,写 if,写 throw,之后即使是最简单的逻辑代码也会变得一团糟。为了解决这个问题,我编写了一个小包装器来检查返回值并在发生某些事情时抛出:
inline int PosixResultChecker( int ret_value, const std::string_view error_message ) {
if ( ret_value < 0 ) [[unlikely]] {
throw std::system_error( errno, std::system_category(), error_message.data() );
} else {
return ret_value;
}
};
int main() {
try {
auto descriptor = PosixResultChecker( open( "/home/riv/tmp.txt", O_RDWR | O_NOCTTY | O_NDELAY ), "Could not open file '/home/riv/tmp.txt'" );
PosixResultChecker( write( descriptor, "Hello world", strlen( "Hello world" ) ), "Could not write to '~/tmp.txt'");
} catch ( std::system_error err ) {
std::cout << err.what() << std::endl;
}
return 0;
}
我真的不喜欢这种方法,但我想不出更好的方法。也许这样的问题经常遇到,并且有某种解决方案或现成的解决方案?
从我所见
在单独的命名空间中,编写具有相同名称、相同参数的包装函数,但如果返回代码不同,则会引发异常。
优点——代码看起来和学生的代码非常相似(好像没有检查),很容易阅读。
缺点 - 很容易出错,忘记你需要关闭资源。名称可能会混淆并调用错误的函数(不是来自包装器)。
第二种方法是给函数起相似的名称(例如,加上 X 后缀)。
const char*std::string/std::array中包含各种“不舒服”的类型参数。第三种方法是使用普通 RAII 编写 OOP 包装器。现在将自动关闭相同的文件。我为 Linux 中的套接字做了这个,结果非常好。它需要一堆强制转换,即套接字描述符参数。而且我还附加了我自己的缓冲区类(这是在标准 11 之前,他们尽可能地退出了),套接字函数可以透明地工作。
我从内存中恢复了代码,这里有一段(这里改进完善)
在你快速做之前,你需要做对:
errno,您应该自己将值重置errno为0。因为他们自己可能不会重置,然后造成尴尬。而你没有。errno和对设置.errno因为他们可能会改变自己的价值errno。而你创建string_view、调用string_view::data、创建system_category。write返回ssize_t,但是,例如,mmap返回一般void *。在您的示例中,假设只有int.write文件描述符会在之后泄漏。std::system_error,则必须确保第三个参数是指向 C 字符串的指针,并且std::string_view根本不需要存储以 null 结尾的字符串。制作 RAII 包装器来封装所有后六功能并检查它们的结果。