我正在尝试使用 system_error
工具来处理我的库中的错误。我将简要讨论该库的结构,以防您发现它对您有所帮助:该库的 namespace 称为 commons
,在此之下我还有另一个 namespace 称为 dynlib
。 dynlib
包含负责加载 .so/.dll 文件的类:
namespace commons {
namespace dynlib {
class DynLibLoader {
};
}
}
DynLibLoader 中可能出现的错误有 LibraryFailedToLoad
、LibraryFailedToUnload
和 SymbolNotFound
。所以我处理错误的想法如下:我将在命名空间dynlib
下添加一个命名空间error
。然后,在该命名空间下,我将为 std::error_codes
定义一个枚举,为 std::error_conditions
定义一个枚举。据我了解, std::error_codes
必须对应于 errno
(Linux) 或 GetLastError
(Win32) 的值,而 >std::error_conditions
到 LibraryFailedToLoad
、SymbolNotFound
等值。所以,这是我的问题:
- 我对
std::error_code
和std::error_condition
的理解是否正确? - 我应该如何知道
errno
和GetLastError()
的所有可能值以便在我的std::error_codes
下定义它们> 枚举?如果 Microsoft 将来向 API 添加额外的错误值怎么办?我是否必须返回源代码并在std::error_codes
的枚举下定义它们? - 如果我们在另一个平台上,并且在发生错误时无法找出确切的系统错误代码怎么办?
- 如果我想为整个公共(public)命名空间使用相同的
std::error_codes
并且只为每个子命名空间定义不同的std::error_condition
怎么办,例如dynlib
。这是一个好习惯吗?我会说是的,因为这将避免重复代码。但这背后有什么问题吗? - 目前,我为每个公共(public)子命名空间使用一个
std::error_category
。这是一个好习惯吗?你认为我应该以不同的方式使用std::error_category
吗?
最佳答案
主要区别在于 std::error_condition
是可移植的(平台无关),而 std::error_code
是平台相关的。通常,低级平台相关代码生成 error_codes
,客户端代码将这些 error_codes
与平台无关 error_conditions
进行比较。
19.5 [syserr] 定义了一长串标准(和可移植的)错误条件(例如 errc::no_such_file_or_directory
),它们明确关联到 errno
的特定值(例如ENOENT
)。因此,您不需要知道系统上生成的 errno
或 GetLastError()
可能值的完整列表。您只需要知道与您的代码相关的标准值。例如,您的库实现可能如下所示:
void MyLibraryClass::foo(std::error_code &ec)
{
// whatever platform dependent operation that might set errno
// possibly with alternative platform-dependent implementations
ec = make_error_code(errno);
}
然后您的客户端代码将检查 error_code
是否匹配任何特定的 error_condition
:
error_code ec;
myLibraryInstance.foo(ec);
if (!ec)
{
// success
}
else if (errc::no_such_file_or_directory == ec)
{
// no_such_file_or_directory
}
else
{
// unknown or unexpected error
}
在您的情况下,您可能会定义自己的错误枚举(只有一个枚举)并将其标记为 error_conditions
以启用自动转换:
namespace commons
{
namespace dynlib
{
enum class errc {LibraryFailedToLoad=1, LibraryFailedToUnload, SymbolNotFound};
}
}
namespace std
{
template<> struct is_error_condition_enum<commons::dynlib::errc> : true_type {};
}
// TODO: implement make_error_code and make_error_condition
然后,您可以将各种平台相关操作的结果转换为适当的 error_condition
(或 error_code
,如果您愿意):
void DynLibLoader::open(std::error_code &ec)
{
// possibly implement the windows version here as well
if (NULL == dlopen(filename, flag))
{
ec = make_error_code(errc::LibraryFailedToLoad);
}
}
您的客户端代码会将错误代码与可能的错误条件进行比较,如上:
error_code ec;
dynLibLoader.open(ec);
if (!ec)
{
// success
}
else if (commons::dynlib::errc::LibraryFailedToLoad == ec)
{
// Library Failed To Load
}
else
{
// unknown or unexpected error
}
请注意,枚举 commons::dynlib::errc::LibraryFailedToLoad
会自动转换为 error_condition
(使用提供的 make_error_condition
方法) 因为 commons::dynlib::errc
被标记为 is_error_condition_enum
。
error_category
到命名空间的映射可能是个人喜好,但似乎有点人为。在这种特定情况下,确实为 dynlib
命名空间有一个类别是有意义的,但很容易找到让类别分布多个命名空间有意义的示例。在某些情况下,将所有不同的错误枚举放在一个唯一的命名空间中可能是有意义且实用的(例如 commons::errors
)。
关于c++ - 了解 C++11 中的 <system_error> 工具,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21821673/