c++ initializer_list迭代器返回错误的值

initializer list - C++ initializer_list iterator returning wrong value

本文关键字:错误 返回 迭代器 initializer list c++      更新时间:2023-10-16

我有一个这样定义的类:

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作为迭代器变成一个悬垂的"指针"。