C 11返回值和错误对
C++11 Return value and error pair
作为C 11引入移动语义,我想知道该函数是否可以返回值和操作状态。实际上,实施并不难,但是我将开始一个新的巨大项目,不知道我应该这样做还是使用老式的东西。所以我对您的意见非常好奇。
请考虑以下符号:
class File
{
FILE *file = nullptr;
public:
Result<void> open(const char *fileName);
Result<void> close();
Result<size_t> size();
Result<void> seek(size_t newPosition);
Result<size_t> position();
Result<char> readCharacter();
};
现在让我们分析一个用法示例:
Result<void> processFile(const char *fileName)
{
File file;
auto result = file.open(fileName);
if (!result.isSuccess())
return result;
auto fileSize = file.size();
if (!fileSize.isSuccess())
return fileSize;
for (size_t i = 0; i < fileSize; i++) {
auto character = file.readCharacter();
if (!character.isSuccess())
return character;
if (character < 'a' || character > 'z')
return Error::invalidData;
// processfileCharacter(character);
}
return Error::success;
}
如您所见,错误管理变得非常简单。此外,当我编写仅标头代码时,启用优化时,GCC和MSVC都会产生非常最佳的代码。我非常喜欢这种符号,看不到任何严重的缺点。但是我很想听听您的意见。
实施
如果您想测试它,请享受代码:
enum class Error: int
{
success,
unknown,
invalidData
// ...
};
结果类:
template <typename Type = void>
class Result
{
Error error = Error::success;
Type data;
public:
Result() = default;
Result(Result &&result) = default;
Result(const Result &result) = default;
template <typename OtherType> Result(const Result<OtherType> &result) : error(result.error) {}
Result & operator =(Result &&result) = default;
Result & operator =(const Result &result) = default;
template <typename OtherType> Result & operator =(const Result<OtherType> &result) { error = result; return *this; }
Result(const Type &data) : data(data) {}
Result(Type &&data) : data(std::move(data)) {}
Result(const Error &error) : error(error) {}
Result(Error &&error) : error(std::move(error)) {}
operator Type& () { return data; }
operator const Type& () const { return data; }
operator const Error() const { return error; }
bool isSuccess() const { return error == Error::success; }
};
void的专业化:
template <>
class Result<void>
{
Error error = Error::success;
public:
Result() = default;
Result(Result &&result) = default;
Result(const Result &result) = default;
template <typename OtherType> Result(const Result<OtherType> &result) : error(result.error) {}
Result & operator =(Result &&result) = default;
Result & operator =(const Result &result) = default;
template <typename OtherType> Result & operator =(const Result<OtherType> &result) { error = result; return *this; }
Result(const Error &error) : error(error) {}
Result(Error &&error) : error(std::move(error)) {}
operator const Error() const { return error; }
bool isSuccess() const { return error == Error::success; }
};
此方法具有以下主要缺点:
-
当您忘记检查结果时,它将您的代码基础为无声失败的可能性开放。
而是将此代码视为客户端代码示例:
Result<void> processFile(const char *fileName) { File file; auto result = file.open(fileName); // utnapistim was tired when writing this code and forgot to // check the error status in result // (this is a bug) auto fileSize = file.size(); // (1) if (!fileSize.isSuccess()) return fileSize; // ... // rest is the same as your example client code return Error::success; }
丢失错误检查下面的代码默默失败:它将在不应该的情况下执行,而数据无效。
在这种特殊情况下,执行的代码(行
(1)
)在File
类中,并且此可以正确工作(如果File
类会在获得大小之前检查内部状态)。使用您的方法,每当您编写客户端代码时,都必须明确记住要处理错误。在大多数实际情况下,您将在调用低级文件大小函数之前假设该文件::大小检查状态。
不要假设 - 它导致错误。
-
它严重夸大了所有客户端代码,努力完成编译器的工作。考虑此替代客户代码:
void processFile(const char *fileName) { auto file = File{fileName}; // throws on failure auto fileSize = file.size(); // executed only on success for (size_t i = 0; i < fileSize; i++) { auto character = file.readCharacter(); // throws on failure if (character < 'a' || character > 'z') throw invalidData{'expected alphanumeric value'}; // processfileCharacter(character); } return Error::success; }
您的客户端代码较少,并且该代码看起来更简单
您有不变性(当您低于
File
实例的声明时,您知道它是有效的,而无需添加if
语句) -
它严重限制了OO设计的良好原则:
- 当您的构造函数无法运行时会发生什么?您的
File
课程没有。
- 当您的构造函数无法运行时会发生什么?您的
如果您使用异常,则这是一个非问题:不管您是否对其进行测试(Catch Block)。
除非您有强大的理由避免例外,您应该使用它们进行错误处理。
相关文章:
- 方法错误"not all control paths return a value"和方法不返回值
- __int64 CString 返回错误的值 - C++ MFC
- 函数从指针 c++ 中获取错误的值并返回错误的答案
- 不断收到错误消息,并非所有控制路径都返回值
- 除法函数返回错误的值
- CUDA返回值错误35的含义是什么
- 不从函数返回值会导致段错误
- C++ std::tm 从 std::chrono::time_point 转换后返回错误的值
- g++ 抛出错误而不返回值
- 合并排序返回错误的值
- 检查Windows激活状态返回错误的值
- 错误C4716:rectionDownLog:必须返回值
- 如何避免使用多个if-else来检查返回值是否为错误代码?
- 函数模板中的无效转换错误,返回值取决于其泛型类型
- GMock 的"WillOnce"和"Return"不会因错误的返回值而失败
- 使用C ,使用SFINAE测试静态成员的存在,返回错误的值
- C 11返回值和错误对
- c 中的getenv返回错误的值
- 如何修复包含错误的错误必须返回值
- 存储在静态常量整数 (C++) 中的对数函数的错误返回值