【问题标题】:Compiler error when attempting to access std::map element with operator[]尝试使用 operator[] 访问 std::map 元素时出现编译器错误
【发布时间】:2013-09-13 03:47:31
【问题描述】:

我正在尝试按键访问地图数据结构的元素,但出现编译器错误。我已经使用 typedefs 定义了我的地图数据结构,以简化地图实例化的语法。可以看到,key 是string 类型,数据是自定义GameComponent 对象:

typedef map<string, GameComponent*> ComponentMap;
typedef map<string, GameComponent*>::iterator ComponentMapIter;
typedef map<string, GameComponent*>::const_iterator ComponentMapCIter;

在GameComponent 的派生类中,我正在为存储在我的地图中的每个唯一 GameComponent 对象创建标准复合模式方法以及访问器。但是,使用数组下标运算符访问访问器中的对象会导致编译器错误:

void Character::add(const string& key, GameComponent* comp)
{
    m_components->insert( make_pair(key, comp) );
}

void Character::remove(const string& key)
{
    m_components->erase(key);
}

Armor* Character::getArmor() const
{
    // ERROR:
    return static_cast<Armor*>(m_components["Armor"]);
}

Weapon* Character::getWeapon() const
{
    // ERROR:
    return static_cast<Weapon*>(m_components["Weapon"]);
}

Attributes* Character::getAttributes() const
{
    // ERROR:
    return static_cast<Attributes*>(m_components["Attributes"]);
}

编译器错误的输出显示“无效类型”错误,这让我摸不着头脑:

/Users/Dylan/Desktop/RPG/character.cpp: In member function 'Armor* Character::getArmor() const':
/Users/Dylan/Desktop/RPG/character.cpp:66: error: invalid types 'ComponentMap* const[const char [6]]' for array subscript
/Users/Dylan/Desktop/RPG/character.cpp: In member function 'Weapon* Character::getWeapon() const':
/Users/Dylan/Desktop/RPG/character.cpp:71: error: invalid types 'ComponentMap* const[const char [7]]' for array subscript
/Users/Dylan/Desktop/RPG/character.cpp: In member function 'Attributes* Character::getAttributes() const':
/Users/Dylan/Desktop/RPG/character.cpp:76: error: invalid types 'ComponentMap* const[const char [11]]' for array subscript

【问题讨论】:

    标签: c++ data-structures map compiler-errors typedef


    【解决方案1】:

    看来m_components 的类型是ComponentMap*。 当您编写m_components["Armor"] 时,编译器会将其解释为访问"Armor"-ComponentMaps 的动态数组的第一个元素,这没有任何意义。

    你想要的是(*m_components)["some string"]。这将调用ComponentMap 的operator[],但正如Luchian Grigore 和Olaf Dietsche 所提到的,std::map::operator[] 没有 const 重载,所以这也会失败。剩下的唯一选择是使用find。

    简化版将是:

    Armor* Character::getArmor() const
    {
        return static_cast<Armor*>(m_components->find("Armor")->second);
    }
    
    Weapon* Character::getWeapon() const
    {
        return static_cast<Weapon*>(m_components->find("Weapon")->second);
    }
    
    Attributes* Character::getAttributes() const
    {
        return static_cast<Attributes*>(m_components->find("Attributes")->second);
    }
    

    此代码与原始示例的行为不同,如果 m_components 没有 "Armor"、"Weapon" 和 "Attributes" 元素,则此代码将失败。 如果您使用 C++11,我们可以得到的最接近的是显式处理元素的缺失并返回 0 或 nullptr。

    最终正确的 C++03 兼容版本:

    Armor* Character::getArmor() const
    {
        ComponentMapCIter i = m_components->find("Armor");
        if (i != m_components->end())
            return static_cast<Armor*>(i->second);
        return 0;
    }
    
    Weapon* Character::getWeapon() const
    {
        ComponentMapCIter i = m_components->find("Weapon");
        if (i != m_components->end())
            return static_cast<Weapon*>(i->second);
        return 0;
    }
    
    Attributes* Character::getAttributes() const
    {
        ComponentMapCIter i = m_components->find("Attributes");
        if (i != m_components->end())
            return static_cast<Attributes*>(i->second);
        return 0;
    }
    

    【讨论】:

    • 是的,这是我最终使用的那个。谢谢。
    【解决方案2】:

    由于std::map 中的operator[] 不是const,因此您不能在const 方法中使用它(当然是在成员上)。

    在 C++11 之前使用 at (C++11) 或 find 和迭代器。

    相关:Why does std::map not have a const accessor?

    【讨论】:

    • 谢谢!这正是我的问题
    【解决方案3】:

    getArmor()、getWeapon() 和 getAttributes() 定义为 const,但 m_components[] 可能会修改 m_components。所以你要么不定义你的方法const,要么改用std::map::find。

    Armor* Character::getArmor() const
    {
        auto i = m_components->find("Armor");
        if (i != m_components->end())
            return static_cast<Armor*>(i->second);
    
        return nullptr;
    }
    

    【讨论】:

    • auto 是 C++11 特性吗?它不能使用我的 GNU 编译器版本,我认为它是 C++11 之前的版本......
    • @Dylan 试试吧。它已经与-std=c++0x 选项一起存在。所以如果你有一个合理的当前 gcc(至少 gcc 4.6),它会工作。
    • @Dylan 仅供参考,auto 已与 gcc-4.4 -std=c++0x (2009-04-21) 一起使用,nullptr 已与 gcc-4.6 -std=c++0x (2011-03-25) 一起使用。跨度>
    • 谢谢,这些是在特定的头文件中提供的吗?
    • @Dylan 不需要头文件。当您将-std=c++0x 添加到命令行时(或在gcc 4.7 的情况下添加-std=c++11),auto 和/或nullptr 可用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-17
    • 2023-04-10
    相关资源
    最近更新 更多