再次获取 std::map 会更改前一个迭代器
Getting again a std::map changes the previous iterator
我找不到任何类似的问题。
在我调用 getMap 的那一刻,之前的迭代器似乎发生了变化:
//IF I COMMENT THE EVIL PRINT, THE PROBLEM DOES NOT OCCUR
std::cout << "EVIL PRINT" << std::endl;
Something something;
auto mapElement = something.getTheMap().find("A");
std::cout << "Before: " << mapElement->first << std::endl;
something.getTheMap();
std::cout << "After: " << mapElement->first << std::endl << std::endl;
/****************************************************************************************/
//WITH SHARED POINTERS, THE EVIL PRINT IS NOT NECCESARY TO MAKE THE PROBLEM OCCUR
std::shared_ptr<Something> somePtr;
auto mapElement2 = something.getTheMap().find("A");
std::cout << "Before: " << mapElement2->first << std::endl;
something.getTheMap();
std::cout << "After: " << mapElement2->first << std::endl << std::endl;
输出:
EVIL PRINT
Before: A
After: B
Before: A
After: B
完整代码可在此处运行https://coliru.stacked-crooked.com/a/66b48636a476ddb7
这是通缉行为吗?发生了什么事?
您没有在问题中包含最重要的部分,即
std::map <std::string, int> getTheMap() {
return theMap;
}
getTheMap
return 是一个副本,所以 getTheMap().find("A");
return 是一个临时对象的迭代器(在调用完成后不再存在)。
因此,该迭代器引用了一个不再存在的对象,它是一个 dangling 迭代器。取消引用它(就像您对 mapElement->first
所做的那样)会调用 未定义的行为
最惯用的修复方法是 getTheMap
到 return 的引用,例如:
std::map <std::string, int>& getTheMap() {
return theMap;
}
您有未定义的行为,因为您在其生命周期之外引用地图。
getTheMap()
returns map by value,这意味着你得到了原始地图的副本。您永远不会将此副本保存在任何地方,因此迭代器在创建后立即变得悬空。
Something something;
auto mapElement = something.getTheMap().find("A"); //temporary map used here
// temporary map is gone and mapElement is invalid
根据你的需要,你可以return参考地图(这将允许从外部修改内部地图):
std::map <std::string, int>& getTheMap() {
return theMap;
}
或者在使用迭代器时,保存复制映射以确保它存在
auto map = something.getTheMap();
auto mapElement = map.find("A");
我找不到任何类似的问题。 在我调用 getMap 的那一刻,之前的迭代器似乎发生了变化:
//IF I COMMENT THE EVIL PRINT, THE PROBLEM DOES NOT OCCUR
std::cout << "EVIL PRINT" << std::endl;
Something something;
auto mapElement = something.getTheMap().find("A");
std::cout << "Before: " << mapElement->first << std::endl;
something.getTheMap();
std::cout << "After: " << mapElement->first << std::endl << std::endl;
/****************************************************************************************/
//WITH SHARED POINTERS, THE EVIL PRINT IS NOT NECCESARY TO MAKE THE PROBLEM OCCUR
std::shared_ptr<Something> somePtr;
auto mapElement2 = something.getTheMap().find("A");
std::cout << "Before: " << mapElement2->first << std::endl;
something.getTheMap();
std::cout << "After: " << mapElement2->first << std::endl << std::endl;
输出:
EVIL PRINT
Before: A
After: B
Before: A
After: B
完整代码可在此处运行https://coliru.stacked-crooked.com/a/66b48636a476ddb7
这是通缉行为吗?发生了什么事?
您没有在问题中包含最重要的部分,即
std::map <std::string, int> getTheMap() {
return theMap;
}
getTheMap
return 是一个副本,所以 getTheMap().find("A");
return 是一个临时对象的迭代器(在调用完成后不再存在)。
因此,该迭代器引用了一个不再存在的对象,它是一个 dangling 迭代器。取消引用它(就像您对 mapElement->first
所做的那样)会调用 未定义的行为
最惯用的修复方法是 getTheMap
到 return 的引用,例如:
std::map <std::string, int>& getTheMap() {
return theMap;
}
您有未定义的行为,因为您在其生命周期之外引用地图。
getTheMap()
returns map by value,这意味着你得到了原始地图的副本。您永远不会将此副本保存在任何地方,因此迭代器在创建后立即变得悬空。
Something something;
auto mapElement = something.getTheMap().find("A"); //temporary map used here
// temporary map is gone and mapElement is invalid
根据你的需要,你可以return参考地图(这将允许从外部修改内部地图):
std::map <std::string, int>& getTheMap() {
return theMap;
}
或者在使用迭代器时,保存复制映射以确保它存在
auto map = something.getTheMap();
auto mapElement = map.find("A");