在这种情况下,C ++会在编译时进行数组边界检查吗?

时间:2017-08-03 14:35:34

标签: c++ arrays c++11 indexoutofboundsexception

受到" C++ HTML template engine that uses compile time HTML parsing"的启发,我试图编写一个示例类来检查字符串中的第一个字符是a

int dummy[0];
class Test
{
public:
    constexpr Test(const char *p):p_(p){}
    constexpr void check()const
    {
        if (p_[0]!='a')
            dummy[1]=0;
    }
    const char *p_;
};


constexpr Test operator"" _test(const char *pszText, size_t)
{
  Test t(pszText);
  t.check();
  return t;
}


int main()
{
    //dummy[1] = 0;
    constexpr Test t = "baa"_test;
}

效果很好(Ubuntu上的GCC7.1)。如果第一个char不是a,则会产生编译错误:

main.cpp:29:24: error: array subscript value ‘1’ is outside the bounds
of array ‘dummy’ of type ‘int [0]’
constexpr Test t = "baa"_test;

让我感到困惑的是,如果我将代码更改为:

int main()
{
    dummy[1] = 0; //no compile error anymore
}

我想知道C ++何时报告数组越界错误。

1 个答案:

答案 0 :(得分:3)

constexpr要求编译器评估代码。并且,因为在C ++抽象机器的上下文中,dummy[1]是未定义的行为,它必须发出诊断。 (这可能是警告或错误。但是,g++clang++都选择将此错误。)

然而,仅仅因为dummy[1]在C ++抽象机器的上下文中是未定义的行为,并不意味着其他东西不能定义行为。这意味着不一定要拒绝代码(如果编译器本身不需要使用它)。它只是未定义的行为,而不是错误。

例如,编译器编写器将使用越界数组访问,并且因为他们正在编写编译器,所以他们可以确保发生的行为是所需的行为。一个很好的例子是数组内存管理,其中返回的指针通常是一个字超过分配的内存的开头(因为大小也需要分配。)所以当编译器编写者需要读取他或她可能做的大小时{ {1}}。

话虽这么说,在这种情况下触发编译器错误的更好方法是简单地使用静态断言:((size_t const*)ptr)[-1]