我有一个这样定义的类:
initializer_list<string> choices;
initializer_list<string>::iterator current_choice;
bool has_choices = false;
MenuItem(Position position, string prompt) { this->position = position; this->prompt = prompt; }
MenuItem(Position position, string prompt, initializer_list<string> choices) : MenuItem(position, prompt) {
this->choices = choices;
this->current_choice = this->choices.begin();
this->text = *(this->current_choice);
this->has_choices = true;
}
当前菜单项定义为MenuItem* current_menu_item = &menuItems[menuItemIndex];
当我在构造函数中迭代initializer_list时,将输出正确的值。但是在后面的代码中,当我尝试切换值时,像这样:
if (c == KEY_RIGHT) {
if (current_menu_item->has_choices)
{
if (current_menu_item->current_choice != current_menu_item->choices.end()) {
current_menu_item->current_choice++;
current_menu_item->text = *(current_menu_item->current_choice);
}
}
}
它显示了下一个菜单项对象的initializer_list的第一个值,我按右键,然后崩溃。如果下一个对象被选中,我按右键,它就崩溃了。
对象被放入一个像这样的向量
menuItems.push_back(MenuItem(Position(5, 15), "Religion: ", { "*", "*", "*", "Protestant" }));
menuItems.push_back(MenuItem(Position(30, 5), "Do you smoke? ", { "Yes", "No" }));
我试着在整个代码的不同点调试,但我似乎无法确定它在哪里或为什么会出错。
没关系,有两个人指出我应该使用常规容器而不是initializer_list。谢谢大家的回答。我现在觉得自己很笨。我所要做的就是将initializer_list更改为vector,而不更改任何其他代码。
选自《工作草案c++, 2012-11-02》
例如,如果我将初始化列表复制到18.9初始化器列表[support.initlist]
initializer_list类型的对象提供了对const e类型对象数组的访问。[注:一对指针或一个指针加一个长度是initializer_list的明显表示。]Initializer_list用于实现8.5.4中指定的初始化器列表。复制初始化列表并不复制底层元素。
std::vector
中,它就可以完美地工作。您应该将choices
定义为常规容器,而不是std::initializer_list
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
struct A {
A(const std::initializer_list<std::string> &args) : v(args) {}
void dump() {
std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "n"));
}
std::vector<std::string> v;
};
int main(int argc, char **argv)
{
A a({"Hello, ", "world!"});
a.dump();
return 0;
}
不应该在解引用迭代器之后(而不是之前)进行自增操作吗?
current_menu_item->text = *(current_menu_item->current_choice);
current_menu_item->current_choice++;
否则,有可能对end迭代器解引用。
还有另一个问题,正如mfontanini指出的那样,当您调用MenuItem(Position(5, 15), "Religion: ", { "*", "*", "*", "Protestant" })
等时,初始化列表在表达式末尾到期,这意味着您的内部初始化列表指向无效内存(初始化列表仅复制指针)。解决方案是使用像std::vector
这样的标准容器。
第二个构造函数按值复制选项。因此,current_choice
作为迭代器的有效性取决于参数选择的活动性。像{ "*", "*", "*", "Protestant" }
这样的参数保存在堆栈中,因此如果调用push_back
的方法返回,那么choices
可能会消失,并且current_choice作为迭代器变成一个悬垂的"指针"。