【问题标题】:C++ macro to replace .at() with []用 [] 替换 .at() 的 C++ 宏
【发布时间】:2019-04-06 00:29:09
【问题描述】:

如果我使用.at() 而不是[] 访问向量或字符串中的元素,我经常遇到索引越界错误。但是,at() 由于边界检查,将我的程序减慢了 5 倍。

我正在尝试编写一个宏来将.at(someVariable) 替换为[someVariable],这样我就可以取消对宏的注释,而不是手动将每个.at() 替换为[]。我已阅读 cppreference.com 上有关宏的文档,但似乎无法设计出获得此功能的方法。

【问题讨论】:

    标签: c++


    【解决方案1】:

    一般来说,我会避免使用这种宏,因为它们是“不可见的”(因此更改后的语义对任何不知情的人都隐藏起来)并且可以更改实际上期望 at 抛出的代码的功能超出范围,即使在发布版本中也是如此。如果有的话,我会定义一些突出的东西,例如全大写的AT

    幸运的是,这实际上并不是必需的,因为“三大”C++ 运行时已经具有内置功能,可以有条件地在operator[] 上启用边界检查(这还具有比at 更具可读性的优势):

    顺便说一句,其中一些错误(实际上溢出分配的大小,而不仅仅是向量的“逻辑有效”大小)也可以使用address sanitizer(在 gcc 和 clang 上为-fsanitize=address)或 valgrind 发现(慢!)和类似的工具。

    【讨论】:

      【解决方案2】:

      这是不涉及宏的一种方式 - 它使用 c++17 的 if constexpr 来方便:

      #include <vector>
      
      constexpr bool safe_mode = true;  // or false
      
      template<class Container>
      auto at(Container& v, std::size_t i) -> decltype(auto)
      {
          if constexpr (safe_mode)
              return v.at(i);
          else
              return v[i];
      }
      
      int& test(std::vector<int>& v)
      {
          return at(v, 6);
      }
      

      【讨论】:

      • 为什么decltype(auto) 尾随?
      • @CruzJean 如果你的意思是我为什么选择这样写,可能是出于习惯。我编写了相当多的模板代码,我发现让所有函数/方法的类型可供我使用是很有用的。所以我倾向于对尾随返回类型进行标准化。话虽如此,我看到我在上面的代码中混合了样式。 :)
      • 啊,我只是好奇它是否有一些我不知道的细微差别。
      • 一年前,在我们应用程序的一个主要项目负责人的建议下,我开始在我的代码中主要使用尾随返回类型(几乎完全),我发现它们更具可读性。这与“几乎总是自动”相结合,生成的 C++ 代码解析得更加清晰。我知道,这都是意见问题。
      【解决方案3】:

      您可以使用数组解引用运算符的全名:

      #define at(x) operator[](x)
      

      (x) 部分不是必需的,但只会在 at 后跟参数时替换它,而不是单独替换单词。您还需要在包含所有标准头文件的之后定义这个,否则它将替换具有它的类中的at 成员函数声明,从而导致编译错误。

      【讨论】:

      • 为什么不需要 .在宏之前?它不应该替换 .也是?
      • @user3586940 您不能替换宏中的.,因为. 不能在宏名称中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-28
      • 1970-01-01
      • 1970-01-01
      • 2016-03-26
      • 2021-12-21
      相关资源
      最近更新 更多