在 C++ std::streams 中,失败后,如何获取失败原因?必需:线程安全且 Windows 和 Linux 通用(或至少 Msvc/Gcc)
In C++ std:: streams, after a failure, how to get a failure reason? Required: threadsafe and common to Windows and Linux (or at least Msvc/Gcc)
对不起,奇怪的标题。限于 150 个字符,因此无法使用正确的句子。
假设我已完成以下操作以发现我的文件流出现问题:
std::ofstream ofs;
do_stuff_with(ofs);
// streams don't throw on error because C++ [edit: we can make them do so, but the .what()s aren't very user-friendly]
// so we have to check for failure manually
if(!ofs){
auto fail_code = errno; // threadsafe on Win/Linux
// but what goes here?
}
1) 错误:
不是线程安全的
2) strerror_s:不在 GCC 中?或者是?
3) strerror_r: 不在 Msvc 中?或者是?
4) #ifdef/#define/etc:糟糕,但可能是唯一的选择
我确实做了一些搜索,但我没有找到 "this will definitely work in a sensible yet slightly platform-dependent way" 答案...也就是说,我觉得这是 "obviously a duplicate question",但我找不到原来的.. .
这是我能想到的最好的。这是 "yuck" 的答案,但至少您可以将 "yuck" 放在一个函数中并将其隐藏在某个 cpp 文件中的某个地方。 std::ios 当然也包括 boost 流。
需要#ifdefs 所以这是作弊。我相信 Visual Studio 默认情况下 #defines _WIN32,所以至少你不必自己设置该基础结构。
void check_stream(std::ios & stream)
{
if (!stream){
char err[1024] = { 0 };
#ifdef _WIN32
strerror_s(err, errno);
#else
strerror_r(errno, err, 1024);
#endif
throw MyException(err);
}
}
我自己的解决方案让我很伤心,所以希望能有更好的解决方案出现。但是时间是有限的,所以只要屈服于黑暗面,使用这样的东西,然后继续你的生活。 :P
try{
boost::filesystem::ifstream ifs("testfile");
check_stream(ifs);
}
catch (std::exception & e){
std::cout << e.what(); // "No such file or directory"
}
您始终可以使用 std::system_error
:
抛出您自己的异常
#include <cerrno>
#include <fstream>
#include <iostream>
#include <system_error>
int main()
{
try
{
std::ofstream foo{"/root/bar.baz"};
foo << "bla" << std::endl;
foo.close();
if(!foo)
throw std::system_error{errno, std::generic_category()};
}
catch(const std::system_error& err)
{
std::cout << "Error: " << err.code() << " - " << err.what() << std::endl;
}
return 0;
}
这个returnsError: generic:13 - Permission denied
.
自 C++11 起,您可以为此使用 class std::error_code
:
std::cout << std::error_code{errno, std::generic_category()}.message();
事实上,你甚至可以做得比这短一点:
std::cout << std::generic_category().message(errno);
虽然我必须说我发现第一个更地道一点。
作为旁注,还有std::system_category()
,它似乎在很大程度上等同于Unix上的generic_category()
,但在Windows上,它可以用来翻译Windows API 返回的错误码如GetLastError()
等
这与 std::system_error
异常中也使用的 class 相同,但如果您只想获取错误,则无需创建异常的实例消息。
对不起,奇怪的标题。限于 150 个字符,因此无法使用正确的句子。
假设我已完成以下操作以发现我的文件流出现问题:
std::ofstream ofs;
do_stuff_with(ofs);
// streams don't throw on error because C++ [edit: we can make them do so, but the .what()s aren't very user-friendly]
// so we have to check for failure manually
if(!ofs){
auto fail_code = errno; // threadsafe on Win/Linux
// but what goes here?
}
1) 错误: 不是线程安全的
2) strerror_s:不在 GCC 中?或者是?
3) strerror_r: 不在 Msvc 中?或者是?
4) #ifdef/#define/etc:糟糕,但可能是唯一的选择
我确实做了一些搜索,但我没有找到 "this will definitely work in a sensible yet slightly platform-dependent way" 答案...也就是说,我觉得这是 "obviously a duplicate question",但我找不到原来的.. .
这是我能想到的最好的。这是 "yuck" 的答案,但至少您可以将 "yuck" 放在一个函数中并将其隐藏在某个 cpp 文件中的某个地方。 std::ios 当然也包括 boost 流。
需要#ifdefs 所以这是作弊。我相信 Visual Studio 默认情况下 #defines _WIN32,所以至少你不必自己设置该基础结构。
void check_stream(std::ios & stream)
{
if (!stream){
char err[1024] = { 0 };
#ifdef _WIN32
strerror_s(err, errno);
#else
strerror_r(errno, err, 1024);
#endif
throw MyException(err);
}
}
我自己的解决方案让我很伤心,所以希望能有更好的解决方案出现。但是时间是有限的,所以只要屈服于黑暗面,使用这样的东西,然后继续你的生活。 :P
try{
boost::filesystem::ifstream ifs("testfile");
check_stream(ifs);
}
catch (std::exception & e){
std::cout << e.what(); // "No such file or directory"
}
您始终可以使用 std::system_error
:
#include <cerrno>
#include <fstream>
#include <iostream>
#include <system_error>
int main()
{
try
{
std::ofstream foo{"/root/bar.baz"};
foo << "bla" << std::endl;
foo.close();
if(!foo)
throw std::system_error{errno, std::generic_category()};
}
catch(const std::system_error& err)
{
std::cout << "Error: " << err.code() << " - " << err.what() << std::endl;
}
return 0;
}
这个returnsError: generic:13 - Permission denied
.
自 C++11 起,您可以为此使用 class std::error_code
:
std::cout << std::error_code{errno, std::generic_category()}.message();
事实上,你甚至可以做得比这短一点:
std::cout << std::generic_category().message(errno);
虽然我必须说我发现第一个更地道一点。
作为旁注,还有std::system_category()
,它似乎在很大程度上等同于Unix上的generic_category()
,但在Windows上,它可以用来翻译Windows API 返回的错误码如GetLastError()
等
这与 std::system_error
异常中也使用的 class 相同,但如果您只想获取错误,则无需创建异常的实例消息。