std :: map at function总是抛出异常

时间:2014-01-22 01:28:42

标签: c++ c++11

我有一个基本功能,可以检查单词是否为键。问题是我的try catch块总是捕获out_of_range异常,即使密钥存在。此问题仅在我的isExclusion函数中出现。如果我在isExclusion函数外部检查一个静态字符串,那么就不会抛出异常。

此外,是否有更好或更有效的方法来检查密钥是否存在?我宁愿不必遍历密钥列表。

#ifndef TITLES_H_
    #define TITLES_H_

    #include <algorithm>
    #include <string>
    #include <vector>
    #include <map>

    static std::map<std::string, int> exclusions;
    static std::vector<std::string> titles;

    bool isExclusion(std::string word);

#endif

#include "titles.h"
#include <iostream>

bool isExclusion(std::string word)
{
    try
    {
        exclusions.at(word);    
    }
    catch (std::out_of_range e)
    {
        return false;
    }

    return true;
}

#include <iostream>
#include "titles.h"

int main()
{
    exclusions["is"] = 1;
    exclusions["the"] = 1;
    exclusions["of"] = 1;
    exclusions["and"] = 1;
    exclusions["a"] = 1;
    exclusions["but"] = 1;
    exclusions["as"] = 1;

    titles.push_back("Descent of Man");
    titles.push_back("The Ascent of Man");
    titles.push_back("The Old Man and The Sea");
    titles.push_back("A Portrait of the Artist As a Young Man");
    titles.push_back("A Man is a Man but Bubblesort IS A DOG");
    std::sort(titles.begin(), titles.end());

    try
    {
        exclusions.at("the");
    }
    catch(std::out_of_range e)
    {
        std::cout << "Not found\n";
    }
    std::cout << "Exclusion?: " << isExclusion("hello") << std::endl;
    std::cout << "Exclusion?: " << isExclusion("the") << std::endl;

    for(auto i = titles.begin(); i != titles.end(); i++)
    {
        std::cout << *i << "\n";
    }

    return 0;
}

3 个答案:

答案 0 :(得分:2)

你的问题在于这一行:

static std::map<std::string, int> exclusions;

通过将此变量定义为static,您将在两个单独的翻译单元中创建两个单独的mapmain()正在使用一个maptitles.cpp正在使用另一个extern std::map<std::string, int> exclusions; 。相反,声明变量如下:

titles.cpp

。 。 。然后将此行添加到std::map<std::string, int> exclusions; 文件中:

static

这将导致全局变量对所有翻译单元可见,并且只有一个实际地图。

通常,在头文件中使用struct关键字是一个坏主意(在class或{{1}}中除外,以声明类变量)。有一些例外,但它们是图书馆作者通常担心的深奥场景。

答案 1 :(得分:2)

static std::map<std::string, int> exclusions;

exclusions定义为staticstatic全局变量的范围仅限于各自的编译单元。这样就可以在多个编译单元中重用名称。

您在两个编译单元中按#include "titles.h"包含此行。因此,您实际上创建了两个具有相同名称的映射,每个映射都限制在其编译单元中。

main

中的这些行
exclusions["is"] = 1;
exclusions["the"] = 1;
exclusions["of"] = 1;
exclusions["and"] = 1;
exclusions["a"] = 1;
exclusions["but"] = 1;
exclusions["as"] = 1;
因此,

在与功能

不同的地图上运行
bool isExclusion(std::string word)
{
    try
    {
        exclusions.at(word);    
    }
    catch (std::out_of_range e)
    {
        return false;
    }

    return true;
}

在另一个单位。第二个单元中的exclusions实际上总是空的。

您需要删除static关键字并将定义移至其中一个单位(最佳main)。要在另一个单元中使用该变量,您必须将其声明为extern

extern std::map<std::string, int> exclusions;

然而,根本不使用全局变量并将地图和单词向量的引用传递给函数会好得多。当你在它时,也让它们成为const引用。 (该功能不会修改它们。)

bool isExclusion(const std::map<std::string, int>& exclusions, const std::string& word)

答案 2 :(得分:0)

回答问题: 有没有更好或更有效的方法来检查密钥是否存在?

执行以下操作:

if (exclusions.find(word) != exclusions.end())
{
    // no, it does not exist
}
else
{
    // yes, you found it, use 
    // exclusions.at(word)
    // safely
}

实际上,如果我没记错的话,如果在元素不存在时只使用“ exclusions.at(word)”,它将为此键创建一个空元素。