在构建基于std :: map的容器时,我遇到了意外行为:检索非现有键的值并不提供使用默认构造函数构造的新对象。
我在这里缺少什么?
简化的测试用例程序:
#include <cstdio>
#include <algorithm>
#include <map>
#include <string>
static std::string to_lower(const std::string& str)
{
std::string lower_label;
std::transform(str.begin(), str.end(), lower_label.begin(), ::tolower);
return lower_label;
}
class Int {
public:
Int () : i(0) { }
Int (int _i) : i(_i) { }
int val() const { return i; }
private:
int i;
};
std::map<std::string, Int> ints;
Int GetInt(const std::string& label)
{
std::string lower_label = to_lower(label);
return ints[lower_label];
}
void AddInt(Int image, const std::string& label)
{
std::string lower_label = to_lower(label);
ints[lower_label] = image;
}
int main()
{
Int k;
printf ("default Int: %d\n", k.val());
AddInt(Int(5), "I5");
Int i = GetInt("i5");
printf ("existing Int: %d\n", i.val());
Int j = GetInt("LaLa");
printf ("non-existing Int: %d\n", j.val()); // expecting 0
return 0;
}
输出:
default Int: 0
existing Int: 5
non-existing Int: 5
答案 0 :(得分:3)
您的transform
写入空字符串,因此程序具有未定义的行为。
在实践中发生的事情是lower_label
在返回时仍然长度为零,所以每次调用to_lower
时都会得到相同的键:空字符串。这意味着您的地图有一个条目,每次调用GetInt
都会返回相同的条目。
但是,由于您有未定义的行为,您很幸运,它不会崩溃或擦除您的磁盘。
在尝试写入之前,您需要使用back_insert_iterator
或正确设置字符串大小。
或者:
std::string lower_label;
std::transform(str.begin(), str.end(), std::back_inserter(lower_label), ::tolower);
或者:
std::string lower_label;
lower_label.resize(str.size());
std::transform(str.begin(), str.end(), lower_label.begin(), ::tolower);
答案 1 :(得分:2)
更改您的to_lower
功能(您也不需要它static
),以便它可以放置小写字符:
std::string to_lower(const std::string& str)
{
std::string lower_label;
std::transform(str.begin(), str.end(), std::back_inserter(lower_label), ::tolower);
return lower_label;
}
然后没关系: 默认Int:0 现有的Int:5 不存在的Int:0