如果我有一个将地图作为私人成员的课程,例如
class MyClass
{
public:
MyClass();
std::map<std::string, std::string> getPlatforms() const;
private:
std::map<std::string, std::string> platforms_;
};
MyClass::MyClass()
:
{
platforms_["key1"] = "value1";
// ...
platforms_["keyN"] = "valueN";
}
std::map<std::string, std::string> getPlatforms() const
{
return platforms_;
}
在我的主要功能中,这两段代码会有区别吗?
代码1:
MyClass myclass();
std::map<std::string, std::string>::iterator definition;
for (definition = myclass.getPlatforms().begin();
definition != myclass.getPlatforms().end();
++definition){
std::cout << (*definition).first << std::endl;
}
代码2:
MyClass myclass();
std::map<std::string, std::string> platforms = myclass.getPlatforms();
std::map<std::string, std::string>::iterator definition;
for (definition = platforms.begin();
definition != platforms.end();
++definition){
std::cout << (*definition).first << std::endl;
}
在Code2中,我刚刚创建了一个新的map变量来保存从getPlatforms()函数返回的映射。
无论如何,在我的真实代码中(我无法发布实际代码,但它直接对应于此概念)第一种方式(Code1)导致运行时错误,无法访问某个位置的内存。
第二种方式有效!
你能否告诉我这两段不同代码之间的理论基础?
答案 0 :(得分:7)
getPlatforms()
按值返回地图,而不是引用,这通常是一个坏主意。
你已经展示了为什么这是一个坏主意的一个例子:
getPlatforms().begin()
是地图上的迭代器,在使用迭代器之前消失,getPlatforms().end()
是与同一原始地图不同的副本上的迭代器。
答案 1 :(得分:1)
你能否告诉我这两段不同代码之间的理论基础?
按值返回时,会返回数据的深层副本。
当您调用myclass.getPlatforms().begin();
和myclass.getPlatforms().end();
时,您实际上构建了两个数据副本,然后从一个副本获取begin迭代器,从另一个副本获取结束迭代器。然后,比较两个迭代器的相等性; 这是未定义的行为。
导致运行时错误,无法访问某个位置的内存。
这是因为初始化了definition
,然后删除了用于创建它的临时对象,使迭代器指向的数据无效。然后,您尝试通过迭代器使用数据。
答案 2 :(得分:-2)
您遇到的问题是您应该使用const_iterator
而不是iterator
。这是因为函数getPlatforms
是const
限定的,而地图iterator begin()
中的函数不是;您必须使用const
限定const_iterator begin() const
来明确告诉编译器您不会修改该类的任何成员。
注意:这只是代码1的情况,顺便返回const&