从std::map迭代访问其second成员内的std::deque元素时出现指针地址重复及访问异常问题
兄弟,你这个问题的核心是局部对象生命周期结束后产生的悬空指针,再加上容器返回值的小坑,咱们一步步拆解清楚:
问题1:局部变量Ruta ruta导致的悬空指针
你在addNuevaRuta函数里创建了一个局部的Ruta ruta对象,然后通过linkAeroRuta把这个局部对象的指针存到了Aerolinea的aeroroutes deque里。但局部变量的生命周期只限于函数内部——当addNuevaRuta执行完毕,这个ruta就会被销毁,对应的内存地址就变成了无效的「悬空指针」。
而且因为栈内存的复用特性,每次调用addNuevaRuta时,这个局部变量在栈上的位置大概率是重复的,所以你会看到所有输出的指针地址完全一样。这时候你再通过这些指针访问对象成员,属于未定义行为,自然会得到错误的输出。
问题2:getRutas()返回容器副本而非引用
你的Aerolinea::getRutas()方法返回的是std::deque<Ruta*>的副本,不是引用。这意味着你在迭代it_airlines.second.getRutas()的时候,其实是在操作一个临时生成的deque副本——虽然这不是你当前问题的核心,但会带来不必要的性能开销,甚至可能引发其他隐藏问题。
修复方案
1. 解决悬空指针问题:确保Ruta对象的生命周期有效
你需要让aeroroutes里存储的指针指向一个生命周期足够长的对象,这里有两种靠谱的思路:
思路A:复用你已有的routes容器
你已经在VuelaFlight里有一个routes容器,用来存储Ruta对象。那我们可以直接在这个容器里构造对象,然后把容器内对象的地址存入aeroroutes:
void VuelaFlight :: addNuevaRuta(const std::string &icao, const std::string &idAeroOrig, const std::string &idAerDest){ // 直接在routes容器末尾构造新的Ruta对象,获取它的引用 this->routes.emplace_back(); Ruta& ruta = this->routes.back(); auto airline_it = this->airlines.lower_bound(icao); if(airline_it == this->airlines.end()){ throw std::out_of_range("VuelaFlight :: addNuevaRuta -> No existe aerolinea con esa identificacion"); } ruta.setCompany(&airline_it->second); Aeropuerto airport; airport.setIata(idAeroOrig); auto it_airport = std::lower_bound(this->airports.begin(), this->airports.end(),airport); ruta.setOrigin(it_airport.base()); airport.setIata(idAerDest); it_airport = std::lower_bound(this->airports.begin(), this->airports.end(),airport); ruta.setDestination(it_airport.base()); // 现在存的是routes容器内对象的地址,生命周期和容器一致 airline_it->second.linkAeroRuta(ruta); }
思路B:使用智能指针管理动态分配的对象
如果你不想依赖routes容器,也可以用std::shared_ptr或std::unique_ptr来管理Ruta对象的内存,避免手动释放:
// 修改Aerolinea的aeroroutes为智能指针容器 std::deque<std::shared_ptr<Ruta>> aeroroutes; // 修改linkAeroRuta方法 void Aerolinea::linkAeroRuta(std::shared_ptr<Ruta> ruta) { this->aeroroutes.push_back(ruta); } // 修改addNuevaRuta void VuelaFlight :: addNuevaRuta(const std::string &icao, const std::string &idAeroOrig, const std::string &idAerDest){ auto ruta = std::make_shared<Ruta>(); auto airline_it = this->airlines.lower_bound(icao); if(airline_it == this->airlines.end()){ throw std::out_of_range("VuelaFlight :: addNuevaRuta -> No existe aerolinea con esa identificacion"); } ruta->setCompany(&airline_it->second); // ... 其他逻辑不变 ... airline_it->second.linkAeroRuta(ruta); this->routes.push_back(*ruta); // 如果还需要存副本的话 }
2. 修改getRutas()返回引用
把getRutas改成返回容器的引用,避免不必要的拷贝:
// 非const版本,允许修改容器 std::deque<Ruta*>& Aerolinea :: getRutas(){ return this->aeroroutes; } // const版本,用于只读场景 const std::deque<Ruta*>& Aerolinea :: getRutas() const { return this->aeroroutes; }
补充说明
为什么你在linkAeroRuta里访问是正常的?因为那时候局部变量ruta还在函数的生命周期内,指针是有效的;但函数执行完毕后,这个对象就被销毁了,之后再访问这些指针就属于未定义行为,结果自然是错误的。
备注:内容来源于stack exchange,提问作者Juan Montes Trujillo

