0

我有一个问题,使用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;
}
4

5 回答 5

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 就足以消除这种可能性。

于 2010-02-01T18:57:17.477 回答
2

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

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

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

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

delete在清除/销毁它之前记住向量中的所有值!

或者,当然,您可以使用 std::string/CString/whatever 代替 char 数组,并通过具有可安全复制的结构完全避免该问题。

于 2010-02-01T18:46:48.400 回答
1

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

struct MyStruct {
   std::string sourceAddress;
   int lastSeen;
   int beaconReceived;
};
于 2010-02-01T18:56:33.720 回答
0

你的代码在我看来没问题。您是否有可能没有传递正确的向量?我的意思是,如果您的个人向量在您尝试添加第三个条目之前以某种方式重置为其原始的 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.
}

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

于 2010-02-01T18:33:30.833 回答
0

对我来说似乎很奇怪:也许//snip代码的一部分有问题?

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

于 2010-02-01T18:36:28.037 回答