3

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

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 处的值。但是,使用第二种方法时,如果找不到密钥(原因很明显),我的应用程序会出现段错误。我究竟做错了什么?

4

3 回答 3

5

如果 return 语句真的看起来像

return &(value) it->second;

那么有几件事可以说:

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

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

  3. 对某种类型的转换的需求源于您曾经const_iterator存储搜索结果的事实。显然你做了一个错误的尝试来抛弃it->second你的(value)演员阵容。正确的方法可能如下所示

     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在这种情况下你应该使用 inside。

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

    value* FindValues(key someKey)
    

    但使用普通iterator的里面。

    你现在拥有的是两者的某种混合体,这就是让你求助于奇怪演员的原因。(事实上​​,你的班级可能需要这两个版本。一个可以通过另一个实现。)

于 2012-07-12T21:13:43.637 回答
3

typedef的 s 非常具有误导性。这是错误的行:

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;

您实际上是在返回一个本地对象的地址,该对象将在函数返回后立即销毁。

于 2012-07-12T21:14:59.540 回答
0

所以,这个变种会更好。

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;
}
于 2012-07-12T21:06:55.010 回答