tags:

views:

161

answers:

6
+1  Q: 

C++ vector problem

I have the following class declaration:

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:
    DEMData();
    //DEMData(const DEMData &d);
    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);
    //~DEMData();
};

I am creating a vector to hold objects of the above type like so:

vector<DEMData> dems;

If I were to push_back 100 objects into this vector, then all 100 objects will have the exact same values as the 100th element.

Below is the code snippet:

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);
      }
  }

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

Why would all elements have the same values?

+4  A: 

Are you doing the push_back in the loop? If not, demData won't change.

If your push_back is within the loop, the values of demData are dependent on the attr[i] values. If those don't change, members of demData won't change.

Liz Albin
+1  A: 

push_back() makes a copy internally, but your DEMData class has no copy constructor, so all of the elements in the vector end up pointing to the same data. When you modify one, you modify all. Since the last element is modified last, you get all of the previous elements mirroring the last one.

HTH

EightyEight
No, they are all copies. If you'd do something like `dems[3].byteOrder = "abc"` only that element will contain the new string. Your point would only be true if the actual strings were to be modified like `copy.byteOrder[5] = 'x'`, but those strings are `const`.
sth
My thinking was; there's no copy constructor. So, when push_back makes a copy of the reference, it performs a shallow copy of const char pointers. So all the char pointers are still pointing to the same location. The only data that will be "properly" copied are the int bit fields. No?
EightyEight
+1  A: 

You seem to call push_back after the end of the for-loop, so that only the last element will be stored in the vector. Is that your intention?

Also the objects might directly store the char* from the attr array, so make sure that the memory used there stays valid and is not overwritten/freed later on.

sth
A: 

Make sure you are creating a new value for the DEMData inside the loop. If you do this :

DEMData dem;

for( int i = 0; i < 100 ; i++ )
{
    modifyDem( dem, i );
    vec.push_back(dem);
}

The vector will only contain the information of the last one modified (because the memory of the object gets overwritten every time).

If you do this :

for( int i = 0; i < 100 ; i++ )
{
    DEMData dem;

    modifyDem( dem, i );
    vec.push_back(dem);
}

You should be o.k.

JoMo
A: 

You should make sure you variable attr is being properly modified in every iteration. Your snippet doesn´t make it clear, but you are always reading the same range from attr. If by any chance you forgot to change this variable for each iteration, you will end up with the same elements in your vector everytime.

fogo
A: 

This looks exactly like http://stackoverflow.com/questions/2314196/push-back-to-a-vector to me...is there something different this time?

Assuming that:

  1. The for loop you included is inside another 0-99 for loop
  2. attr[] is maintained somehow between the two for loops and contains either char* or std:strings

The way push_back works is it makes a copy of the data passed in. When you pass a stack object demData all of its attributes are being copied with a default copy constructor which simply copies the actual pointer which (which a simplistic version of the set functions would just pass on through). So even though you set the values into demData each pass through the loop, all you're doing is making 100 items in the vector that are all pointing at the exact same string data: The last data decoded from the source file.

If you posted the code for one of the functions like SetEngUnit that would help confirm this.

Options are:

  1. Make the char* in the class std::string, which should manage all the memory for you.
  2. Implement the copy constructor and operator= for your class to do a deep copy.
  3. Make sure when you call the set methods that you pass in a distinct pointer each time. You'll need to make sure you clean it up right or you leak memory.
Mark B