push_back to Vector - PullRequest
       39

push_back to Vector

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

У меня странная проблема. У меня есть вектор, на который я хотел бы добавить объекты, например:

vector<DEMData>* dems = new vector<DEMData>();
DEMData* demData = new DEMData();
// Build DEMDATA

dems->push_back(*demData);

В векторе будет несколько сотен объектов DEMData. Проблема в том, что когда этот код закончен, все элементы равны последнему элементу, «отодвинутому» назад к вектору?

Почему другие объекты переопределяются в векторе?

редактирование:

Класс DemData является простым, просто структура данных с установщиками и получателями:

    class DEMData
{
private:
    int bitFldPos;
    int bytFldPos;
    const char* byteOrder;
    const char* desS;
    const char* engUnit;
    const char* oTag;
    const char* valType;
    int index;
public:
    void SetIndex(int index);
    int GetIndex() const;
    void SetValType(const char* valType);
    const char* GetValType() const;
    void SetOTag(const char* oTag);
    const char* GetOTag() const;
    void SetEngUnit(const char* engUnit);
    const char* GetEngUnit() const;
    void SetDesS(const char* desS);
    const char* GetDesS() const;
    void SetByteOrder(const char* byteOrder);
    const char* GetByteOrder() const;
    void SetBytFldPos(int bytFldPos);
    int GetBytFldPos() const;
    void SetBitFldPos(int bitFldPos);
    int GetBitFldPos() const;
    friend std::ostream &operator<<(std::ostream &stream, DEMData d);
};

EDIT:

Я читаю файл XML и строю объекты DEMData на основе атрибутов каждого элемента xml:

DEMData demData;
  for (i = 0; attr[i]; i += 2)
  {
      if(strcmp(attr[i],"BitFldPos") == 0)
      {
      demData.SetBitFldPos(*attr[i + 1] - '0');
      }
      else if(strcmp(attr[i],"BytFldPos") == 0)
      {
        char* pEnd;
        int tmp = strtol(attr[i + 1],&pEnd,10);
        demData.SetBytFldPos(tmp);
      }
      else if(strcmp(attr[i],"ByteOrder") == 0)
      {
        demData.SetByteOrder(attr[i + 1]);
      }
      else if(strcmp(attr[i],"DesS") == 0)
      {
      demData.SetDesS(attr[i + 1]);
      }
      else if(strcmp(attr[i],"EngUnit") == 0)
      {
        demData.SetEngUnit(attr[i + 1]);
      }
      else if(strcmp(attr[i],"OTag") == 0)
      {
        demData.SetOTag(attr[i + 1]);
      }
      else if(strcmp(attr[i],"ValTyp") == 0)
      {
        demData.SetValType(attr[i + 1]);
      }
      else if(strcmp(attr[i],"idx") == 0)
      {
        char* pEnd;
        int tmp = strtol(attr[i + 1],&pEnd,10);
        demData.SetIndex(tmp);
      }
      //printf(" %s='%s'", attr[i], attr[i + 1]);
  }


  // Insert the data in the vector.
  dems.push_back(demData);

Ответы [ 5 ]

6 голосов
/ 23 февраля 2010

Почему вы выделяете вектор новым? Почему вы выделяете свой временный DEMData объект новым?

A vector хранит копию того, что вы передаете ему, а не сами данные, поэтому, если вы не удаляете объект DEMData, который вы выделили с новым, вы теряете память каждый раз, когда вы вставьте элемент в вектор. Точно так же вы настраиваете себя на проблемы утечки памяти, динамически выделяя вектор.

Что касается того, почему все объекты в векторе, похоже, содержат одни и те же данные, вполне вероятно, что у вас их больше - вероятно, использование указателей в сочетании с неверным ctor для копирования, что в итоге делает несколько мелких копий местами этого не должно быть - но поскольку вы не показали нам этот код, это только предположение.

Редактировать: Теперь, когда вы добавили код для своего класса DEMData, похоже, что приведенное выше предположение было верным - у вас есть указатели, а пользовательский экземпляр копирования отсутствует, поэтому вы получаете мелкую копию.

В качестве первого шага я избавился бы от всех членов-указателей char и заменил бы их на std::string s. С int членами должно быть все в порядке - при копировании их будут скопированы значения.

Edit2: Учитывая то, что вы делаете с этими переменными-членами, похоже, что вы должны рассмотреть возможность использования двух std::map s - одного для std::string переменных и одного для int переменных.

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

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

Вам нужно сделать так, чтобы ваш вектор хранил DEMData*, а push_back указатель, а не значение, на которое указывает.

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

Полагаю, строки в объектах одинаковы. Предположительно вы используете тот же объект demData для заполнения вектора.

И так как вы используете конструктор копирования по умолчанию, все копии содержат одинаковые (char *) указатели. Если вы измените содержимое памяти, на которую ссылаются эти указатели, все копии «увидят» изменения.

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

Вашему классу DEMData требуется конструктор копирования и деструктор для управления памятью строк. В настоящее время (вероятно) происходит то, что создается объект DEMData, вставленный в вектор, который создает новый экземпляр DEMData с теми же значениями указателя. Затем вы уничтожаете исходный DEMData (поскольку деструктора нет), который оставляет указатели в векторе висящими. Затем, когда вы создаете новый DEMData, он получает те же ячейки памяти (случайно), и в конце все объекты указывают на те же местоположения.

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

Я не уверен, что в этом случае это как-то связано с самим вектором ... То, как вы используете указатели на вектор и demData (вместо размещения их в стеке) выглядит немного подозрительно .

Я ожидаю, что нормальный код C ++ будет выглядеть так:

vector<DEMData>* dems = new vector<DEMData>();
DEMData demData
// Build DEMDATA

dems->push_back(demData);
...
delete dems;

Можете ли вы вставить остальную часть своего кода? или, может быть, цикл, который строит demData?

...