答案是:这取决于您要编译的C ++标准。所有代码在所有标准中的格式都完全正确‡,以下行除外:
char * s = "My String";
现在,字符串文字具有类型const char[10]
,我们正在尝试初始化指向它的非常量指针。对于除char
字符串文字系列之外的所有其他类型,此类初始化始终是非法的。例如:
const int arr[] = {1};
int *p = arr; // nope!
但是,在C ++ 11之前的版本中,对于字符串文字,第4.2 / 2节中有一个例外:
可以将不是宽字符串文字的字符串文字(2.13.4)转换为类型为“ 指针 ”的右值;[...]。无论哪种情况,结果都是指向数组第一个元素的指针。仅当存在显式的适当的指针目标类型时才考虑此转换,而在通常需要从左值转换为右值时则不考虑这种转换。[注意:不建议使用此转换。见附件D. ]
因此,在C ++ 03中,代码非常完美(尽管已弃用),并且具有清晰可预测的行为。
在C ++ 11中,该块不存在-转换为的字符串文字没有这种例外char*
,因此代码与int*
我刚才提供的示例一样格式错误。编译器有义务发出诊断信息,理想情况下,在这种情况下(例如明显违反C ++类型系统的情况),我们希望好的编译器不仅在这方面符合要求(例如,发出警告),而且还会失败彻底
理想情况下,该代码不应编译-但应同时在gcc和clang上进行编译(我认为是因为尽管有十多年不赞成使用这种类型的系统漏洞,但仍有很多代码会以很少的收益被破坏)。代码格式错误,因此无法推断代码的行为。但是考虑到这种特定情况以及以前允许的历史记录,我认为将结果代码解释为隐式是不合理的const_cast
,例如:
const int arr[] = {1};
int *p = const_cast<int*>(arr); // OK, technically
这样,该程序的其余部分就可以很好地工作了,因为您再也无需实际触摸s
。通过非指针读取创建的const
对象const
完全可以。通过这样的指针写一个创建const
对象是未定义的行为:
std::cout << *p; // fine, prints 1
*p = 5; // will compile, but undefined behavior, which
// certainly qualifies as "unpredictable"
由于无需s
在代码中的任何地方进行修改,因此该程序在C ++ 03中很好,应该无法在C ++ 11中编译,但无论如何都可以进行-鉴于编译器允许这样做,因此在其中仍然没有未定义的行为† 。考虑到编译器仍在[错误地]解释C ++ 03规则,我认为没有什么会导致“不可预测的”行为。s
尽管写,但所有的赌注都关闭了。在C ++ 03和C ++ 11中。
†尽管如此,顾名思义,格式错误的代码不会产生合理的行为预期
‡除非不是,请参阅Matt McNabb的回答