c++ - 了解 C++11 中的 <system_error> 工具

标签 c++ c++11 error-handling error-code std-system-error

我正在尝试使用 system_error 工具来处理我的库中的错误。我将简要讨论该库的结构,以防您发现它对您有所帮助:该库的 namespace 称为 commons,在此之下我还有另一个 namespace 称为 dynlibdynlib 包含负责加载 .so/.dll 文件的类:

namespace commons {
    namespace dynlib {
        class DynLibLoader {
        };
    }
}

DynLibLoader 中可能出现的错误有 LibraryFailedToLoadLibraryFailedToUnloadSymbolNotFound。所以我处理错误的想法如下:我将在命名空间dynlib下添加一个命名空间error。然后,在该命名空间下,我将为 std::error_codes 定义一个枚举,为 std::error_conditions 定义一个枚举。据我了解, std::error_codes 必须对应于 errno (Linux) 或 GetLastError (Win32) 的值,而 >std::error_conditionsLibraryFailedToLoadSymbolNotFound 等值。所以,这是我的问题:

  • 我对 std::error_codestd::error_condition 的理解是否正确?
  • 我应该如何知道 errnoGetLastError() 的所有可能值以便在我的 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)。因此,您不需要知道系统上生成的 errnoGetLastError() 可能值的完整列表。您只需要知道与您的代码相关的标准值。例如,您的库实现可能如下所示:

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/

相关文章:

c++ - 使用 MSYS2/Mingw32 编译 gRPC

c++ - 为什么不更新 vector 内结构内的 bool 值?

r - 绘制 ggmap 时 Shiny 找不到对象

c++ - 错误 C2679 : binary '<<' : no operator found which takes a right-hand operand of type 'std::string' (or there is no acceptable conversion)

php - 第 36 行的 fatal error : Call to undefined function session_register() in/home/bakewell/public_html/inventory/config. inc.php

python - 为什么我看不到 readline.set_completion_display_matches_hook 的错误?

C++ 'string' 未在 header 中命名类型

c++ - 删除虚拟继承

c++ - 如何在 visual studio 2010 中使用 openAl

C++:在迭代器之间的计算距离上被类型混淆