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

Weird behavior with map.find and a pointer to a vector

本文关键字:指针 向量 find map      更新时间:2023-10-16

我有一个向量对到向量向量的映射,看起来像这样:

std::map<std::pair<uint16, uint16>, std::vector<std::vector<uint32> > >

映射是在类的构造函数中填充的。这个类提供了一个公共方法,该方法返回指向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;
}

这就是它变得奇怪的时候。在FindValues返回的向量上迭代时,所有子向量的第一个值都是一个大的负数(如-1818161232)。但如果我使用类似的函数

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

则该值是正常的。只有所有子向量的索引0处的值才会发生这种情况。不过,对于第二种方法,如果找不到键(原因很明显),我的应用程序就会出错。我做错了什么?

如果返回语句真的看起来像

return &(value) it->second;

然后有几件事可以说:

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

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

  3. 需要某种类型的强制转换是因为您使用了const_iterator来存储搜索结果。很明显,你做了一个错误的尝试,试图用你的(value)演员阵容来消除it->second的惊愕。正确的方法可能看起来如下

     return const_cast<value *>(&it->second);
    

    但是你为什么一开始就使用const_iterator呢?正确的做法是使用常规的iterator,只进行

     return &it->second;
    

    没有任何额外的铸件。

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

    const value* FindValues(key someKey) const
    

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

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

    value* FindValues(key someKey)
    

    但内部使用普通CCD_ 15。

    你现在拥有的是两者的某种混合,这就是为什么你不得不求助于奇怪的演员阵容。(事实上,你的类中可能需要两个版本。一个可以通过另一个实现。)

您的typedef非常具有误导性。这是一条错误的线路:

return &(value)it->second;

看似简单的C样式类型转换实际上是对std::vector的复制构造函数的调用。这行可以重写为

return &std::vector<std::vector<uint32> >(it->second)

当你重写这一行时,奇怪结果的原因变得显而易见:

std::vector<std::vector<uint32> > result (it->second);
return &result;

实际上,您返回的是一个本地对象的地址,一旦函数返回,该对象就会被销毁。

所以,这个变体会更好。

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 &const_cast<value&>(it->second);
    return 0;
}