C++代码纯度

kov*_*rex 10 c++ error-handling refactoring

我正在使用C++环境,并且:
a)我们被禁止使用异常
b)应用程序/数据服务器代码可以评估不同种类的请求

我有简单的类封装服务器操作的结果,也在内部用于那里的许多功能.

class OpResult
{
  .....
  bool succeeded();
  bool failed(); ....
  ... data error/result message ...
};
Run Code Online (Sandbox Code Playgroud)

当我试图让所有函数变得小而简单时,会产生很多这样的块:

....
OpResult result = some_(mostly check)function(....);
if (result.failed())
  return result;
...
Run Code Online (Sandbox Code Playgroud)

问题是,让宏看起来像这样并在任何地方使用它是不好的做法吗?

#define RETURN_IF_FAILED(call) \
  {                            \
    OpResult result = call;    \
    if (result.failed())       \
      return result;           \
  }
Run Code Online (Sandbox Code Playgroud)

我知道有人可以称之为讨厌,但有更好的方法吗?你会建议用什么其他方法来处理结果并避免大量的膨胀代码?

Ste*_*end 9

这是一个折衷.您正在交换代码大小以模糊逻辑.我更喜欢将逻辑保持为可见.

我不喜欢这种类型的宏,因为它们破坏了Intellisense(在Windows上),并调试了程序逻辑.尝试return在函数中的所有10个语句上放置一个断点- 而不是检查,只是return.尝试单步执行宏中的代码.

关于这一点最糟糕的是,一旦你接受了这一点,很难与一些程序员喜欢用于常见迷你任务的30行怪物宏争论,因为他们"澄清了事情".我已经看到了代码,其中不同的异常类型通过四个级联宏以这种方式处理,导致源文件中有4行,宏实际上扩展到> 100实线.现在,你减少代码膨胀吗?不,用宏来轻松讲述是不可能的.

反对宏的另一个一般论点,即使在这里显然不适用,也就是能够用难以破译的结果来嵌套它们,或传递导致奇怪但可编译的参数的参数,例如在使用++x两次参数的宏中使用.我总是知道我对代码的立场,我不能说关于宏.

编辑:我应该补充的一点是,如果你真的重复这个错误检查逻辑一遍又一遍,也许在代码中有重构机会.如果确实适用,则不是保证,而是更好的代码膨胀减少方法.查找重复的调用序列并将公共序列封装在自己的函数中,而不是解决每个调用的处理方式.

  • 它是否增加代码膨胀取决于是否有这些宏的替代品.如果宏的替代方法是手动写入100行,那么宏不会增加代码膨胀.如果有替代方案,那么是的,宏是有问题的. (2认同)

Vla*_*lad 5

实际上,我更喜欢其他解决方案.问题是内部调用的结果不一定是外部调用的有效结果.例如,内部故障可能是"找不到文件",但外部故障可能是"配置不可用".因此我的建议是重新创建OpResult(可能将"内部"OpResult打包到其中以便更好地调试).这一切都转向了.NET中"InnerException"的方向.

从技术上讲,在我的情况下,宏看起来像

#define RETURN_IF_FAILED(call, outerresult) \
  {                                         \
    OpResult innerresult = call;            \
    if (innerresult.failed())               \
    {                                       \
        outerresult.setInner(innerresult);  \
        return outerresult;                 \
    }                                       \
  }
Run Code Online (Sandbox Code Playgroud)

该解决方案需要一些内存管理等.

一些纯粹主义者认为没有明确的回报会妨碍代码的可读性.在我看来,明确RETURN作为宏名称的一部分,足以防止任何熟练和专注的开发人员的混淆.


我的观点是,这样的宏不会混淆程序逻辑,相反会使它更清晰.使用这样的宏,您可以以清晰简洁的方式声明您的意图,而另一种方式似乎过于冗长,因此容易出错.让维护者解析相同的构造OpResult r = call(); if (r.failed) return r是浪费他们的时间.

无早返回的另一种方法是施加到每个代码行中的图案像CHECKEDCALL(r, call)#define CHECKEDCALL(r, call) do { if (r.succeeded) r = call; } while(false).这在我看来更糟糕,并且肯定容易出错,因为人们CHECKEDCALL()在添加更多代码时往往忘记添加.

有一个受欢迎的需要用宏检查返回(或一切)似乎是我遗漏语言功能的一个轻微迹象.


kov*_*rex 1

10年后,我将会满意地回答自己的问题,如果我有一台时光机就好了……

我在新项目中多次遇到类似的情况。即使允许例外,我也不想总是将它们用于“正常失败”。

我最终发现了一种编写此类语句的方法。

对于包含消息的通用结果,我使用以下命令:

class Result
{
public:
  enum class Enum
  {
    Undefined,
    Meaningless,
    Success,
    Fail,
  };
  static constexpr Enum Undefined = Enum::Undefined;
  static constexpr Enum Meaningless = Enum::Meaningless;
  static constexpr Enum Success = Enum::Success;
  static constexpr Enum Fail = Enum::Fail;

  Result() = default;
  Result(Enum result) : result(result) {}
  Result(const LocalisedString& message) : result(Fail), message(message) {}
  Result(Enum result, const LocalisedString& message) : result(result), message(message) {}
  bool isDefined() const { return this->result != Undefined; }
  bool succeeded() const { assert(this->result != Undefined); return this->result == Success; }
  bool isMeaningless() const { assert(this->result != Undefined); return this->result == Enum::Meaningless; }
  bool failed() const { assert(this->result != Undefined); return this->result == Fail; }
  const LocalisedString& getMessage() const { return this->message; }

private:
  Enum result = Undefined;
  LocalisedString message;
};
Run Code Online (Sandbox Code Playgroud)

然后,我有一个这种形式的特殊帮助器类(与其他返回类型类似)

class Failed
{
public:
  Failed(Result&& result) : result(std::move(result)) {}
  explicit operator bool() const { return this->result.failed(); }
  operator Result() { return this->result; }
  const LocalisedString& getMessage() const { return this->result.getMessage(); }

  Result result;
};
Run Code Online (Sandbox Code Playgroud)

当这些结合起来时,我可以编写如下代码:

if (Failed result = trySomething())
  showError(result.getMessage().str());
Run Code Online (Sandbox Code Playgroud)

是不是很漂亮?