遍历QButtonGroup::buttons导致程序崩溃的原因解析
问题代码
初始化代码:
auto box1=new QCheckBox; box1->setText("choice1"); auto box2=new QCheckBox; box2->setText("choice2"); QPushButton* button=new QPushButton; connect(button,&QPushButton::clicked,this,&Widget::onClicked); auto group=new QButtonGroup; group->setExclusive(false); group->addButton(box1); group->addButton(box2);
槽函数代码:
void Widget::onClicked() { // 崩溃的写法 std::for_each(group->buttons().begin(),group->buttons().end(),[](QAbstractButton* button){ button->setChecked(!button->isChecked()); }); /* // 正常运行的写法 QList<QAbstractButton *> buttons=group->buttons(); std::for_each(buttons.begin(),buttons.end(),[](QAbstractButton* button){ button->setChecked(!button->isChecked()); }); */ }
崩溃原因解析
QButtonGroup的buttons()方法是值返回,也就是说每次调用该方法,都会创建并返回一个全新的QList<QAbstractButton*>临时对象。
在崩溃的写法里:
group->buttons().begin()是从第一个临时QList对象中获取起始迭代器group->buttons().end()则是从第二个完全独立的临时QList对象中获取结束迭代器
这两个迭代器属于不同的容器实例,用它们组成的范围进行遍历是C++标准中定义的未定义行为。同时临时对象会在当前表达式结束后立即销毁,迭代器会变成悬空迭代器。这种情况下遍历会出现范围错误(比如你看到的循环执行三次),最终访问到非法内存地址导致程序崩溃。
而正常运行的写法中,先将buttons()的返回值赋值给局部变量buttons,此时begin()和end()都来自同一个QList实例,迭代器匹配且容器对象在遍历期间始终有效,因此遍历过程安全且正确。
内容的提问来源于stack exchange,提问作者air
相关产品推荐
相关产品推荐

