1

我有一个这样定义的类:

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 更改为向量,而无需更改任何其他代码。我喜欢 C++。

4

3 回答 3

3

来自“C++ 工作草案,2012-11-02”

18.9 初始化器列表 [support.initlist]
2 类型为initializer_list 的对象提供对类型为const E 的对象数组的访问。[ 注意:一对指针或一个指针加上一个长度将是initializer_list 的明显表示。initializer_list 用于实现 8.5.4 中指定的初始化列表。复制初始值设定项列表不会复制底层元素。——尾注]

如果我将初始化列表复制到一个std::vector例子中,它就可以完美地工作。您应该将 your 定义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;
}
于 2013-03-03T00:26:17.403 回答
1

您不应该在取消引用迭代器之后(而不是之前)递增吗?

current_menu_item->text = *(current_menu_item->current_choice);
current_menu_item->current_choice++;

否则,您可能会取消引用结束迭代器。

此外,另一个问题,正如 mfontanini 所指出的,当您调用MenuItem(Position(5, 15), "Religion: ", { "*", "*", "*", "Protestant" })等时,初始化列表在表达式末尾过期,这意味着您的内部初始化列表指向无效内存(初始化列表仅复制指针)。解决方案是使用标准容器,例如std::vector.

于 2013-03-03T00:24:50.807 回答
0

您的第二个构造函数按值复制选择。因此,current_choice作为迭代器的有效性取决于参数选择的活跃度。像这样的参数{ "*", "*", "*", "Protestant" }被保存在堆栈中,因此如果调用push_back返回的方法choices可能会消失,并且作为迭代器的 current_choice 会变成一个悬空的“指针”。

于 2013-03-03T00:23:10.113 回答