18

我正在尝试使用该system_error工具来处理我的图书馆中的错误。如果你觉得它有帮助,我将简要讨论库的结构: 库的命名空间被调用commons,在这个命名空间下我有另一个命名空间dynlib. dynlib包含负责加载 .so/.dll 文件的类:

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

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

  • 我的理解std::error_code是否std::error_condition正确?
  • 我应该如何知道所有可能的值errnoGetLastError()在我的std::error_codes枚举下定义它们?如果 Microsoft 将来向 API 添加额外的错误值怎么办?我是否必须返回源代码并在我拥有的枚举下定义它们std::error_codes
  • 如果我们在另一个平台上并且在发生错误时无法找出确切的系统错误代码怎么办?
  • 如果我想std::error_codes为整个公共命名空间使用相同的名称,并且只std::error_condition为每个子名称空间定义一个不同的名称,例如dynlib. 这是一个好习惯吗?我会说是的,因为这将避免重复代码。但这背后有什么问题吗?
  • 目前,我std::error_category为公共的每个子命名空间使用一个。这是一个好习惯吗?你认为我应该使用std::error_category不同的方式吗?
4

1 回答 1

12

主要区别在于std::error_condition可移植(独立于平台)而std::error_code依赖于平台。通常,低级平台相关代码生成error_codes,客户端代码将这些代码与error_codes平台无关代码进行比较error_conditions

19.5 [syserr] 定义了一长串标准(和可移植的)错误条件(例如),这些条件与(例如errc::no_such_file_or_directory)的特定值显式关联。因此,您不需要知道系统可能值或在系统上生成的完整列表。您只需要知道与您的代码相关的标准值。例如,您的库实现可能如下所示:errnoENOENTerrnoGetLastError()

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在某些情况下,将所有不同的错误枚举放在一个唯一的命名空间(例如)中可能是有意义和实用的。

于 2015-01-10T00:26:50.127 回答