C++宏将 .at() 替换为 []

C++ macro to replace .at() with []

本文关键字:替换 宏将 at C++      更新时间:2023-10-16

我经常有一个索引越界错误,如果我使用.at()而不是[]来访问向量或字符串中的元素,很容易被捕获。但是,由于边界检查,at()使我的程序减慢了 5 倍。

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

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

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

如果你
  • 使用的是 g++/libstdc++,如果你通过-​D_GLIBCXX_DEBUG你会得到 STL 容器的调试版本,它对operator[]执行边界检查,以及对迭代器的许多其他调试检查;
  • CLang/libc++ 可以执行类似的检查,将_LIBCPP_DEBUG设置为 1;
  • 对于 Visual C++,类似的功能在ITERATOR_DEBUG_LEVEL设置为2的情况下启用(默认情况下已在调试版本中启用)。

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

这里有一种不涉及宏的方法 - 它使用 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);
}

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

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

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