map.find和指向向量的指针的奇怪行为

dav*_*dav 3 c++ pointers vector map

我有一个矢量映射对的映射,如下所示:

std::map<std::pair<uint16, uint16>, std::vector<std::vector<uint32> > >
Run Code Online (Sandbox Code Playgroud)

地图填充在类的构造函数中.这个类提供了一个返回指向std::vector<std::vector<uint32> >(映射值部分)的指针的公共方法,如下所示:

typedef std::pair<uint16, uint16> key;
typedef std::vector<std::vector<uint32> > value;

value* FindValues(key someKey) {
    std::map<key, value>::const_iterator it;
    it = someStore.find(someKey);
    if (it != someStore.end()) 
        return &(value)it->second;
    return NULL;
}
Run Code Online (Sandbox Code Playgroud)

这是奇怪的时候.迭代FindValues返回的向量时,所有子向量都有一个大的负数(例如-1818161232)作为它们的第一个值.但是,如果我使用如下函数:

value FindValues(key someKey) {
    std::map<key, value>::const_iterator it;
    return someStore.find(someKey)->second;
}
Run Code Online (Sandbox Code Playgroud)

......那么价值是正常的.这仅发生在所有子向量的索引0处的值.但是,使用第二种方法,如果找不到密钥,我的应用程序会出现段错误(原因很明显).我究竟做错了什么?

AnT*_*AnT 5

如果return语句看起来真的如此

return &(value) it->second;
Run Code Online (Sandbox Code Playgroud)

然后有几件事可以说:

  1. 如果编译器在没有发出诊断消息的情况下接受它就会中断.在C++中,将内置的一元&应用于非引用的结果是非法的.该(value) it->second表达式生成一个临时对象,即一个右值.您无法使用获取此类对象的地址&.代码甚至不应该编译.

  2. 如果您的编译器接受它作为某种奇怪的"扩展",那么这意味着您确实获取并返回临时对象的地址.然后立即销毁临时对象,使指针指向垃圾.难怪你通过这样的指针看到一些奇怪的值.

  3. 由于您曾经const_iterator存储过搜索结果这一事实,因此需要某种类型的转换.显然你做了一个被误导的企图抛弃it->second你的(value)演员的常数.正确的方法可能如下所示

     return const_cast<value *>(&it->second);
    
    Run Code Online (Sandbox Code Playgroud)

    但是你为什么一开始就使用const_iterator它?正确的做法是使用常规iterator做法

     return &it->second;
    
    Run Code Online (Sandbox Code Playgroud)

    没有任何额外的演员.

  4. 您需要决定FindValue尝试编写哪种方法.如果这应该是一个常量方法,它应该返回const value *并应该声明为const

    const value* FindValues(key someKey) const
    
    Run Code Online (Sandbox Code Playgroud)

    当然,const_iterator在这种情况下你应该使用内部.

    如果您FindValue应该是非常量方法,那么您可以保留当前声明

    value* FindValues(key someKey)
    
    Run Code Online (Sandbox Code Playgroud)

    但使用普通的iterator内部.

    你现在拥有的是两者的某种混合体,这就是让你诉诸怪异演员阵容的原因.(事实上​​,你的课程可能需要两个版本.一个可以通过另一个实现.)