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

C++ 在这种情况下,C++;在编译时进行数组边界检查吗?,c++,arrays,c++11,indexoutofboundsexception,C++,Arrays,C++11,Indexoutofboundsexception,受“”思想的启发,我试图编写一个示例类来检查字符串中的第一个字符是否为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 oper

受“”思想的启发,我试图编写一个示例类来检查字符串中的第一个字符是否为
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)。如果第一个字符不是
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++何时报告数组越界错误。

<代码> CONTXPRP</代码>要求编译器评估代码。而且,因为在C++抽象机的上下文中,哑[1 ] < /C>是未定义的行为,它必须发出诊断。(这可能是警告或错误。但是,

g++
clang++
都选择将此设置为错误。)

<>但是,因为虚设[1 ] < /C>是C++抽象机器上下文中的未定义行为,并不意味着其他东西不定义行为。这意味着代码不必被拒绝(如果编译器本身不需要使用它)。这只是未定义的行为,而不是错误

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


也就是说,在这种情况下触发编译器错误的更好方法是简单地使用静态断言:
static\u assert(p_[0]!='a',“字符串不以'a'开头”)

未定义的行为。我猜它与
constepr
相关?我已经试过了,Clang(4.0和6.0)也做了同样的事情。有趣!GCC
-fsantize=bounds
标志可能有用。请注意,您可以通过完美定义的行为来实现这一点;您可以分配一个
char
缓冲区,确保有足够的对齐,并在构建阵列之前为正确对齐的
大小\u t
留出空间。然后,您可以获取最终的数组指针,转换回char指针,偏移sizeof size\u t,并转换回存储在那里的size\u t。优化器很可能会使机器代码完全相同,就像朴素的UB解释一样。(我唯一不确定的部分是使用新的和动态大小的布局来创建一个新的数组)我之所以提到它,是因为我记得在过去看到过包含非常相似内容的库代码,这是我想要演示的一个很好的示例。但是谢谢你解释没有UB怎么做。我有点想了想,但我脑子里一点也不知道什么时候该选UB,什么时候该选UB,什么时候该选UB?那是从哪里来的?结果我错了。我刚刚检查过,根据3.27,包含UB的程序可能会被拒绝翻译,并显示诊断消息。我修改了答案,使之更准确。注意,这可能是一个错误,但也可能是一个警告。