我使用const_cast来修改initializer_list中的元素,如下所示:
#include <initializer_list>
int main()
{
auto a1={1,2,3};
auto a2=a1;//copy or reference?
for(auto& e:a1)
{
int*p=const_cast<int*>(&e);
++(*p);
}
for(auto& e:a2)
cout<<e;
return 0;
}
不幸的是,在做++(* p)时,这个g ++ 4.9.2编译的程序会抛出SIGSEGV。这个问题不会发生在VC中。
为什么这是我的程序有任何不安全的操作?请帮助,谢谢。
答案 0 :(得分:5)
修改最初声明为const
的数据是未定义的行为,初始化列表的内容始终为const
。
在这种情况下,似乎列表的内容存储在只读页面或某些页面中,并且您收到运行时错误。你很幸运:未定义的行为任何都可能发生。
通过写入const导致的未定义行为的另一个典型示例是当您在一行上修改某些内容时,在下一行上读取它并且修改不会显示。发生这种情况是因为编译器可以假设任何const声明的(未引用的)数据不会改变,因此它可以优化其代码以假定初始值是它始终具有的值。
编译器实际做的其他可能性是编译器注意到你在分支上做了未定义的行为,推断不能逻辑地采用分支,导致进入分支的条件必须是另一个设置,并完全消除一个分支(和/或进入一个分支,其前提条件由上述逻辑证明)。未定义的行为可以节省时间。
您的硬盘可能会被格式化,计算机可能会爆炸,它会将您的网络历史记录通过电子邮件发送给您的父母:编译器可以随时使代码执行任何操作,无论是出于何种原因。
不要做未定义的行为。
答案 1 :(得分:3)
作为上一个问题的I mentioned,initializer_list<T>
的基础数组由const
个对象组成。修改声明为const
的对象是未定义的行为。来自[dcl.type.cv]:
除了可以修改声明为mutable(7.1.1)的任何类成员之外,任何修改const的尝试都是如此 对象在其生命周期(3.8)中导致未定义的行为。
一个可能的未定义行为实例化是SIGSEV,这是你从gcc看到的。另一种可能的实例化是代码工作,这是你在VC中看到的。只是不要这样做。