C ++ std :: map这是正确的做法

时间:2013-09-05 23:08:35

标签: c++ stl

如果这是错误的网站,请提前告知,如果有,请告诉我们。

我编写了一个函数,用于检查特定std::map中是否存在,并想知道这是否是一个很好的做法,并且,是否有人可以抛出任何关于改进的指示。

std::map允许为值接受多种数据类型。

union Variants {

    int asInt;
    char* asStr;


    Variants(int in) { asInt = in; }
    Variants() { asInt = 0;}
    Variants(char* in) { asStr = in; }

    operator int() { return asInt; }
    operator char*() { return asStr; }

};

template<typename T, typename Y>
bool in_map(T value, std::map<T, Y> &map)
{
     if(map.find(value) == map.end()) {
       return false;
   }else{
     return true;
   }
}

然后我可以主要使用以下内容:

 std::map<string, Variants> attributes;

 attributes["value1"] = 101;
 attributes["value2"] = "Hello, world";

 if(in_map<std::string, Variants>("value1", attributes))
 {
    std::cout << "Yes, exists!";
 }

非常感谢任何帮助或建议。对不起,如果这不符合规则或标准。谢谢!

3 个答案:

答案 0 :(得分:3)

我看到你的函数最大的问题是你丢弃了生成的迭代器。

当您检查地图中是否存在某个键时,大多数情况下您希望在此之后检索/使用相关值。在这种情况下使用您的函数会强制您以性能为代价进行双重查找。我只是完全避免使用该函数,并直接编写测试,保留迭代器以供以后使用,以避免无用的查找:

auto it = map_object.find("key");
if (it != map_object.end())
    use(it->second);
else
    std::cout << "not found" << std::endl;

当然,如果您只是检查一个密钥是否存在而不关心相关值,那么您的功能很好(考虑到其他人在评论中告诉您的内容)但我认为其用例非常有限并不值得额外的功能。你可以这么做:

if (map_object.find("key") != map_object.end())
    std::cout << "found, but I don't care about the value" << std::endl;

答案 1 :(得分:0)

  

关于改进的指示。

确定。

template<typename T, typename Y>
bool in_map(T value, const std::map<T, Y> &map)
{
     return map.find(value) != map.end();
}

我将地图作为第一个参数(只是一个偏好)。另外,因为整个东西都适合单行,你可能甚至不需要这个功能。

你也扔掉了返回的迭代器,但既然你没有使用它,那不是问题。

  

除此之外,这在编码实践方面看起来还不错吗?即使用Union还是我可以使用的其他类型如struct?

好吧,使用char*并不是一个好主意,因为char*暗示您可以修改数据。 char*也暗示此指针是动态分配的,您可能希望稍后delete[]该指针。你不能在工会中使用析构函数。如果无法更改文本,则可以使用const char*,否则您可能希望使用不同的数据类型。另请参阅Rule of Three

下一个问题 - 您正在尝试将char *和int放在同一位置。这意味着在某些时候你试图将指针转换为整数。这是一个坏主意,因为在64位平台上,指针可能不适合int,而你只能得到它的一半。

此外,如果您尝试在同一个变量中存储多个不同的值,则不会指示哪个类型存储在任何位置。要做到这一点,你需要将union括在struct中并添加指示存储对象类型的字段(到struct)。但是,在这种情况下,你最终会重新发明轮子。因此,如果您尝试存储“通用”类型,则可能需要查看Boost.AnyBoost.VariantQVariant。但所有这些都需要BIG外部库(boostQt)。

答案 2 :(得分:0)

输入

if(in_map<std::string, Variants>("value1", attributes))

对我来说似乎有些过分,键入所有typename语法让我只想使用map.find函数而不仅仅是为了方便。但是,根据您的编译器,有时可以自动解释模板参数,例如,visual studio将允许这样:

if(in_map(std::string("value1"), attributes))

在这种情况下,我必须构造一个std::string对象来替换char*,但我已经从调用中完全删除了模板定义,编译器仍然会找出{{1} }和T基于给定的参数。

但是,我建议的建议是使用Y来定义您的“功能”。虽然它不是真正的函数,但由于#define实际上只是直接将代码片段替换为源代码,因此它可以使事情变得更容易和视觉上吸引人:

#define

然后你使用它的代码就像这样:

#define in_map(value,map) (map.find(value) != map.end())

你们都得到了不使用函数调用的优化,以及像在PHP中那样的视觉外观。