std :: vector覆盖最终值,而不是增长?

时间:2010-02-01 18:28:59

标签: c++ stl vector standard-library

我遇到的问题是使用vector.push_back(value)覆盖最终值,而不是追加到最后。为什么会这样?我在矢量中有一个样本项,所以它的大小永远不会达到零。以下是代码..

void UpdateTable(vector<MyStruct> *Individuals, MyStruct entry)
{
    MyStruct someEntry;
    bool isNewEntry = true;

    for (int i = 0; i < Individuals->size(); i++)
    {
        if (!(strcmp(Individuals->at(i).sourceAddress, entry.sourceAddress)))
        {
            isNewEntry = false;
            //snip.  some work done here.
        }
    }

    if(isNewEntry)
    {
        Individuals->push_back(entry);
    }
}

这是我的第一个“样本”值,并且将允许向量中的另外一个项目。当添加2个新条目时,第二个将覆盖第一个条目,因此大小永远不会大于2.

编辑:更多代码,因为这显然不是问题?

void *TableManagement(void *arg)
{
      //NDP table to store discovered devices.
      //Filled with a row of sample data.
      vector<MyStruct> discoveryTable;
      MyStruct sample;
      sample.sourceAddress = "Sample";
      sample.lastSeen = -1;
      sample.beaconReceived = 1;
      discoveryTable.push_back(sample);

      srand(time(NULL));
      while(1)
      {
          int sleepTime = rand() % 3;
          sleep(sleepTime);
          MyStruct newDiscovery = ReceivedValue();
          if (newDiscovery.lastSeen != -1000) //no new value from receivedValue()
          {
              UpdateTable(&discoveryTable, newDiscovery);
          }
          printTable(&discoveryTable);
      }
      return NULL;
}

5 个答案:

答案 0 :(得分:3)

我会冒险猜测:

假设MyStruct被声明为

struct MyStruct
{
    const char *sourceAddress;
    // Other Gubbins ...
};

ReceivedValue就像

那样
MyStruct ReceivedValue()
{
    static char nameBuffer[MAX_NAME_LEN];

    // Do some work to get the value, put the name in the buffer

    MyStruct s;
    s.sourceAddress = nameBuffer;
    // Fill out the rest of MyStruct
    return s;
}

现在,你推入向量的每个结构都有sourceAddress指向同一个全局缓冲区,每次调用ReceivedValue它都会用新字符串覆盖该缓冲区 - 所以向量中的每个条目都结束用相同的字符串。

我不能确定没有看到你的其余代码,但我可以肯定,如果你在评论的评论中遵循一些好的C ++风格的建议,这种可能性就会消失。

编辑以澄清:没有必要堆分配你的结构,简单地将sourceAddress声明为std :: string就足以消除这种可能性。

答案 1 :(得分:2)

您要推送到数据库的项目的范围即将到期。当你离开创建它们的{}时,它们就会被破坏 - 因此对它们的引用不再有效。

您需要将其从vector<MyStruct>更改为vector<MyStruct*>(最好使用Boost ::而不是指针的安全指针,但您明白了。)

您正在(有限的)范围内创建项目并将其推送到向量上(当复制 struct 时,其中的字符串不是!)它然后重新使用相同的内存位置(最有可能是经过适当优化)来存储下一个“新”结构和之后的结构,依此类推等等。

相反,在有限范围内创建MyStruct *myObject = new MyStruct并分配其值,然后将指针推送到向量。

在清除/销毁之前,请记住delete矢量中的所有值!!

或者,当然,你可以使用std :: string / CString / whatever而不是char数组,并通过安全复制结构来完全避免这个问题。

答案 2 :(得分:1)

然而,ComputerGuru的答案在另一种选择中有效。您可以为MyStruct创建复制构造函数和重载operator =。在这些操作中,您需要将实际字符串复制到新结构中。在C ++中,结构只不过是具有默认公共访问而不是默认私有访问的类。另一种方法是使用std :: string而不是char *作为字符串值。 C ++字符串已经有这种行为。

struct MyStruct {
   std::string sourceAddress;
   int lastSeen;
   int beaconReceived;
};

答案 3 :(得分:0)

你的代码看起来不错。您是否可能没有传递正确的向量?我的意思是,在您尝试添加第三个条目之前,如果您的Individuals向量被重置为其原始的1条目状态,那么您描述的行为将会出现,然后看起来好像您的第二个条目被覆盖了。

这就是我的意思:

int test_table()
{
  string SampleAddresses[] = {"Sample Address 1", "Sample Address 2"};

  for (int i = 0; i < 2; i++)
  {
     // All this work to build the table *should* be done outside the loop; but we've accidentally put it inside
     // So the 2nd time around we will destroy all the work we did the 1st time
     vector<MyStruct> Individuals;
     MyStruct Sample;
     Sample.sourceAddress = "Sample Address 0";
     Test.push_back(Sample);

     // this is all we meant to have in the loop
     MyStruct NewEntry;
     NewEntry.sourceAddress = SampleAddresses[i];
     UpdateTable(Individuals, NewEntry);
  }

  //Now the table has 2 entries - Sample Address 0 and Sample Address 2.
}

如果这是您的所有代码,那么问题就很明显了。但它可能隐藏在其他一些代码中。

答案 4 :(得分:0)

对我来说似乎很奇怪:可能代码的//snip部分有问题吗?

尝试在push_back调用之前和之后(在调试器中或使用cout)记录向量的大小,并查看isNewEntry变量。