std :: vector перезаписывает окончательное значение, а не растет? - PullRequest
0 голосов
/ 01 февраля 2010

У меня возникла проблема, когда использование 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.

edit: Больше кода, так как это, очевидно, не проблема?

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 ]

3 голосов
/ 01 февраля 2010

Я рискну догадаться:

Предположим, 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, чтобы исключить эту возможность.

2 голосов
/ 01 февраля 2010

Срок действия элементов, которые вы помещаете в базу данных, истекает. Они уничтожаются, когда вы покидаете {}, в котором они были созданы, и поэтому ссылка на них больше не действительна.

Вам нужно изменить его с vector<MyStruct> на vector<MyStruct*> (желательно с использованием безопасных указателей из Boost :: вместо указателей, но вы поняли идею).

Вы создаете элемент в пределах (ограниченной) области и помещаете его в вектор (пока копируется struct , строки в нем , а не !), А затем используются повторно та же самая ячейка памяти (скорее всего, если она правильно оптимизирована) для хранения следующей «новой» структуры, и той, что после, и так далее, и так далее.

Вместо этого в пределах ограниченной области создайте MyStruct *myObject = new MyStruct и назначьте его значения, затем нажмите указатель на вектор.

Не забудьте delete все значения из вектора перед его очисткой / уничтожением !!

Или, конечно, вы могли бы использовать std :: string / CString / what вместо массива char и полностью избежать этой проблемы, имея структуру для безопасного копирования.

1 голос
/ 01 февраля 2010

Ответ ComputerGuru работает, однако, в другом варианте. Вы можете создать конструктор копирования и оператор перегрузки = для MyStruct. В этих операциях вам нужно скопировать фактическую строку в новую структуру. В C ++ структуры - это не более чем классы с общедоступным доступом по умолчанию вместо частного доступа по умолчанию. Другой альтернативой является использование std :: string вместо char * для строкового значения. Строки C ++ уже имеют такое поведение.

struct MyStruct {
   std::string sourceAddress;
   int lastSeen;
   int beaconReceived;
};
0 голосов
/ 01 февраля 2010

Мне кажется странным: Может быть, что-то не так с //snip частью кода?

Попробуйте записать размер вектора до и после вызова push_back (либо в отладчике, либо с помощью cout), а также посмотрите на переменную isNewEntry.

0 голосов
/ 01 февраля 2010

Ваш код выглядит хорошо для меня. Возможно ли, что вы не передаете правильный вектор? Я имею в виду, что описанное вами поведение будет выглядеть, если каким-то образом ваш индивидуальный вектор будет сброшен в исходное состояние с 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.
}

Если бы это был весь ваш код, тогда проблема была бы очевидна. Но это может быть скрыто в некоторых других частях кода.

...