【问题标题】:Why does a map insert change the object member values?为什么地图插入会更改对象成员值?
【发布时间】:2023-03-13 01:32:01
【问题描述】:
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>

class Car {
public:
    Car( float costs, float speed) : costs(costs), speed(speed){}; 

    float getSpeed() const {
        return speed;
    }

    float getCosts() const {
        return costs;
    }

private:
    float costs;
    float speed;
};


class CarManager {
public: 

    CarManager(){};

    void assignCars( std::vector<Car> &cars){
        float costs = 1000.0;

        float inc_costs = 700.0;
        float inc_speed = 50.0; 

        for (size_t i = 0; i <= 10; ++i) {
            float speed = 10.0;
            std::vector<Car*> car_vec;
            for (size_t j = 0; j < 5; ++j) {

                if (j >= i) {
                    cars.push_back(Car(costs, speed));
                    car_vec.push_back(&cars.back());
                }
                speed += inc_speed;
            }

            car_storage.insert( {costs , car_vec }  );
            costs += inc_costs;
        }
    }

    void print(){
        for (const auto & p : car_storage) {
            std::cout << "map[" << p.first << "] = ";
            for (const auto & s : p.second) {   
                    std::cout << "[" << s->getSpeed() <<", " << s->getCosts() << "] , ";
            }
            std::cout << std::endl;
        }
    }

private:
    std::map<float, std::vector<Car*> > car_storage;
};

int main()
{

    std::vector<Car> cars;
    CarManager car_manager;
    car_manager.assignCars(cars);
    car_manager.print();

}

printout 与我的预期有些不同。我将具有成本和速度的汽车推入向量 [cars.push_back(Car(costs, speed))] 中,然后将指向此 Car 的指针推入 Car* 的本地向量中:car_vec.push_back(&amp;cars.back())。接下来,我将键 (costs) 和值 (car_vec) 插入到映射中。当我打印出地图时,这些值不再正确。

以第一种情况为例: 第一个循环 i = 0,内循环 j,因此 (j >= i) 和我 push_back 一个 Car( 1000.0, 10.0)。稍后,地图中包含的内容只是Car(0,0)。对于其他汽车,这也适用,但它们有一些奇怪的值。

map[1000] = [0, 0] , [0, 7.41086e-38] , [0, 7.41063e-38] , [0, 7.41064e-38] , [210, 1700] , 

map[1700] = [0, 7.41092e-38] , [0, 7.41094e-38] , [0, 7.41094e-38] , [210, 1700] , 

map[2400] = [110, 2400] , [160, 2400] , [210, 2400] , 

map[3100] = [160, 3100] , [210, 3100] , 

map[3800] = [210, 3800] ,

我不知道发生了什么。调试向我显示,在将它们插入到 car_storage.insert( {costs , car_vec } ) 的地图中之前,这些值是正常的。

【问题讨论】:

    标签: c++ pointers


    【解决方案1】:

    当你写这个时会发生什么:

    cars.push_back(Car(costs, speed))
    car_vec.push_back(&cars.back())
    

    ?您创建一个 Car 并将其 copy 推送到 cars 向量。在下一行中,您将 指向此向量中的副本的指针。永远不要这样做!在第一个向量大小更改的任何进一步操作中,例如push_backclear 等,它可能会重新分配它的所有内容。 IE。它需要新的内存片段,在那里复制值,删除旧的。指向其内容的旧指针变得无效。

    【讨论】:

    • 好吧,我不知道只有一个副本被推送。我认为从 C++11 开始,std::move() 就可以完成了。那么解决方法是使用 emplace_back 吗?或者我将如何解决这个问题?
    • @SeanM。 emplace_back 允许你构造一个没有副本的对象。但cars.back()的地址仍然可以随时更改。也许一个好方法是保留一个指针向量。它是一种很好的形式,可以为可能的“重”用户类保留一个指针向量。如果不想手动管理内存,可以考虑 vectorunique_ptr>vectorshared_ptr>
    • @SeanM。你是对的,在这段代码中,临时对象将从 C++11 开始移动。但我认为这对这门课没有任何区别。无论如何,问题不是副本。它是指向可变地址或局部变量的指针。
    • 感谢您指出这一点,我会仔细研究智能指针。
    • 这 (coliru.stacked-crooked.com/a/67e4e367d33b272a) 不应该是我之前代码的预期行为吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 1970-01-01
    • 2023-03-07
    相关资源
    最近更新 更多