2016-06-10 50 views
1

我使用的const_cast修改元素的initializer_list内,象下面这样:C++ 11使用指针修改initializer_list中的元素导致SIGSEGV,为什么?

#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)时该克++ 4.9.2编译程序引发SIGSEGV。这个问题在VC中不会发生。

为什么会这样,是有任何不安全的操作我的程序?请帮忙,谢谢。

+1

'auto a2 = a1;'永远不会成为参考,只是一个副本。如果你想要一个引用,你需要像'auto&a2 = a1;'那样显式地指定'' –

+3

你执行了一个'const_cast',然后是一个变种,你想知道你的程序是否“有任何不安全的操作”? –

回答

3

作为I mentioned对于您的上一个问题,initializer_list<T>的底层阵列由const对象组成。修改申报const对象是不确定的行为。从[dcl.type.cv]:

除了任何类成员声明可变(7.1.1)可以被修改,任何试图其寿命(3.8)导致未定义的行为过程中修改一个const 对象。

未定义行为的一个可能实例是SIGSEV,这是您从gcc看到的。另一个可能的实例是代码工作,这是你在VC中看到的。只是不要这样做。

5

修改最初声明为const的数据是不确定的行为,并且初始化程序列表的内容始终为const

在这种情况下,看来该列表中的内容被存储在只读页面或诸如此类,和你得到一个运行时错误。你很幸运:具有未定义的行为任何东西都可能发生。

的因写入到常量未定义行为的另一个典型的例子是,当你修改一行的东西,并在下一行你读它,修改不会显示出来。这是因为编译器可以假定任何常量声明的(未标记)数据不会改变,因此它可以优化其代码假定初始值是它始终拥有价值。

,实际上编译器做其他的可能性是编译器注意到你在分支上做不确定的行为,理由是该分支不能在逻辑上考虑,得出该条件进入分支必须是其他设置,消除一个分支完全(和/或进入一个分支,其前提条件已被上述逻辑证明)。未定义的行为可以时间旅行。

你的硬盘驱动器可以被格式化,电脑可能会爆炸,用电子邮件发送您的网页记录你的父母:一个编译器就可以让代码做任何事情,在任何时候,任何理由或没有。

不要做未定义的行为。