再次获取std :: map会更改以前的迭代器

问题描述 投票:0回答:2

我找不到任何类似的问题。我调用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

这是通缉的行为吗?发生了什么事?

c++ stdmap auto
2个回答
0
投票

您没有在问题中包括最重要的部分,即

std::map <std::string, int> getTheMap() {
        return theMap;
}

getTheMap返回一个副本,因此getTheMap().find("A");将迭代器返回到一个临时对象(在调用完成后该对象不再存在)。因此,迭代器引用的对象不再存在,它是dangling迭代器。取消引用它(就像使用mapElement->first一样)将调用undefined behavior

最惯用的解决方法是getTheMap返回参考,例如:

std::map <std::string, int>& getTheMap() {
        return theMap;
}

0
投票

您具有未定义的行为,因为您在生命周期之外引用映射。

getTheMap()按值返回地图,这意味着您将获得原始地图的副本。您永远不会将这个副本保存在任何地方,因此,迭代器在创建后立即悬而未决。

Something something;
auto mapElement = something.getTheMap().find("A"); //temporary map used here
// temporary map is gone and mapElement is invalid

根据您的需要,您可以通过引用返回地图(这将允许从外部修改内部地图:

std::map <std::string, int>& getTheMap() {
    return theMap;
}

或保存副本映射以确保在使用迭代器时它存在

auto map = something.getTheMap();
auto mapElement = map.find("A");
© www.soinside.com 2019 - 2024. All rights reserved.