Thread: Vectors + Classes = Confusing

  1. #1
    Registered User
    Join Date
    Jun 2003
    Posts
    361

    Vectors + Classes = Confusing

    Hullo again, I've had a few suggestions recently to move towards vectors instead of just regular old arrays, so I've started looking into them with more depth. Here's what I've gotten so far:

    Code:
    //Create a vector with 10 members
    std::vector<int> MyInts(10);
    
    
    //Create a vector with an undefined amount of members
    std::vector<int> MyInts();
    //And later, say I want to add an element to the vector (I.e. the integer 30)
    MyInts.push_back(30)
    And that's all pretty decent with me, but my purpose here is to make a vector of classes.

    Code:
    class cORGANISM
    {
    public:
    	cORGANISM(void);
    	virtual ~cORGANISM(void);
    	
    	void Initialise(int HisAge);
    private:
    	int Age;
    };
    So I've tried going about it like this:
    Code:
    std::vector<cORGANISM> Dude();
    
    Dude.push_back(/*I can't figure out what goes in here*/);
    Dude[0].Initialise(50); //Make this dude 50 years old
    My thoughts for the push_back() are to somehow pass the Constructor?? But I just haven't been able to search up a thread that covers this.

    Thanks for any insight,
    Erik

  2. #2
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    Just construct an object as if you were calling the constructor.
    Code:
    std::vector<cORGANISM> Dude; // Note no () here
    
    Dude.push_back(cORGANISM());
    If the constructor takes multiple arguments, then put them in there.

    What it is most likely doing under the covers is creating a temporary object and then using the copy constructor to make a copy of that object and place it into the appropriate spot in the vector.

  3. #3
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    Ah, that did the trick. I kept on trying Dude.cORGANISM() and other variations, but that does the trick. Thanks jlou.

  4. #4
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    Still sort of on the same topic, I'm just wondering, do Vectors have to be cleaned up in some specific way? I thought they did all of that themselves...

    My reason for asking is that I get a trademark "Would you like to report this error to Microsoft?" window popping up when I exit, if my Vector is greater than 1 in size.

    There are other possible places for this error, but I just thought I'd check to see if this was it first.

  5. #5
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    When a vector object goes out of scope any allocated memory is released.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    In your destructor for the class just call Vector::clear() which will clean up the memory for the vector.

    But it should be cleaned up when it goes out of scope. However I make it a practice to clear the vector before this happens. This is usually in the destructor for the class that makes use of the vector.

  7. #7
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Quote Originally Posted by Epo
    Still sort of on the same topic, I'm just wondering, do Vectors have to be cleaned up in some specific way? I thought they did all of that themselves...
    Yes, vectors handle all memory management by themselves. There's no need to call any routines when the vector is no longer used.

    Bubba, is there any particluar reason that you call clear in the destructor of the class? To me, it just seems to complicate the code for no reason -- one of the advantages of using vector is that you don't have to bother with the destruction.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  8. #8
    Registered User Kybo_Ren's Avatar
    Join Date
    Sep 2004
    Posts
    136
    The only time you should worry about is when you have a vector of pointers that are dynamically allocated.

    I.e.
    Code:
    std::vector<int*> pointers;
    
    pointers.push_back(new int);
    You MUST say:
    Code:
    delete pointers[elem];
    for whatever elements you create.

  9. #9
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    Thanks for the help guys. I've managed to find the problem, and it was a DirectX problem related to the Vector, but not the actual Vector itself. I may toss the Vector::clear() method into the destructor, just for peace of mind.

    In fixing my problem, I had to re-think the use of my vector, and in doing so, I no longer have a vector of my class, but I have a vector of a struct, within that class:
    Code:
    struct KINETICS
    {
    	D3DXVECTOR2 Position;
    	D3DXVECTOR2 Velocity;
    	D3DXVECTOR2 Boundary;
    
    	void Init(int iWidth, int iHeight)
    	{
    		int X, Y;
    
    		X = (rand() / ((RAND_MAX / iWidth) + 1));
    		Y = (rand() / ((RAND_MAX / iHeight) + 1));
    
    		Position = D3DXVECTOR2((float)X, (float)Y);
    		Velocity = D3DXVECTOR2(3.0f, 3.0f);
    		Boundary = D3DXVECTOR2((float)iWidth, (float)iHeight);
    	}
    
    	void Update(void)
    	{
    		if(Position.x < 0.0f)
    		{
    			Position.x = Boundary.x;
    		}
    		else if(Position.x > Boundary.x)
    		{
    			Position.x = 0.0f;
    		}
    		
    		if(Position.y < 0.0f)
    		{
    			Position.y = Boundary.y;
    		}
    		else if(Position.y > Boundary.y)
    		{
    			Position.y = 0.0f;
    		}
    
    		Position = Position + Velocity;
    	}
    };
    
    class cORGANISM
    {
    public:
    	cORGANISM(void);
    	virtual ~cORGANISM(void);
    	
    	HRESULT Initialise(IDirect3DDevice9 *pD3DDevice);
    	void Render(void);
    private:
    	IDirect3DDevice9 *m_pD3DDevice;
    	IDirect3DTexture9 *m_pTexture;
    	ID3DXSprite *m_pSprite;
    
    	std::vector<KINETICS> Movement;
    };
    And it's working nice and dandy. I'm up to having 100 of these organisms travelling across the screen, but I've hit a barrier in capabilities (200 organisms and the frame rate drops very noticeably). But that's for another discussion somewhere else

    I am curious though, how it is okay that I am doing this, when creating my Vector of 100 Movement variables:
    Code:
    Movement.push_back(KINETICS());
    I did that as a hunch when converting my code. I wasn't aware that structs had constructors...

  10. #10
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    in C++ struct and class only have one difference. struct defaults to public class defaults to private. Other then that there is no difference between them.

  11. #11
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    Oooh, jeez, I read that somewhere too. It's getting late and I've been looking at this code for too long Thanks Thantos.

    I'm going to have to start being a bit more careful how I use structs.

    Technically, I should have explicitly defined a constructor/destructor for my struct, like I did for my class then?

  12. #12
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    It depends. Are you using it like a C struct? If you are then you really don't need to write a construct / destructor.

    Personal Opinion Follows:
    If you are going to use methods with structs then you should rename it to class and just declare the public part.
    Example:
    Code:
    struct Foo {
      int x_;
      int x() const { return x_; }
    };
    Should be
    Code:
    class Foo {
      public:
      int x_;
      int x() const { return x_; }
    };

  13. #13
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Illustration of serious memory/resource leak with vectors:

    Code:
     
    class AnimSeq
    {
      std::vector<IDirect3DTexture9 *> Textures;
      std::vector<float> FrameTimes;
      std::vector<unsigned int> FramePositions;
     
      IDirect3DDevice9 *m_pDevice;
     
      public:
    	  AnimSeq(void) {};
    	  ~AnimSequence {};
    	  void Create(IDirect3DDevice9 *_pDevice) {m_pDevice=_pDevice;};
     
    	  void AddFrame(std::string _strFile,float _fTime)
    	  {
    	   IDirect3DTexture9 *_pTemp;
    	   D3DXCreateTextureFromFile(&m_pDevice,_strFile.c_str(),&_pTemp);
    	   Textures.push_back(_pTemp);
    	   FrameTimes.push_back(_fTime);
    	   FramePositions.push_back(0);
    	 }
    };
    Ok what is wrong with this? I have a vector of IDirect3DTexture9 objects. At destruction the memory for the vector is cleared up.....but the Texture interfaces have NOT been released back to COM.

    The vector cleanup code will NOT call Texture->Release() because it has no idea what is in the vector. So even though the memory has been released back to the OS....COM has been royally messed up.

    In the destructor for this you would do:

    Code:
     
    std::vector<IDirect3DTexture9 *>::iterator Image;
     
    while (Image!=Textures.end())
    {
    	(*Image)->Release();
    }
     
    Textures.clear();
    Last edited by VirtualAce; 12-15-2004 at 11:41 AM.

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I believe the only way around this would be to encapsulate the textures in a class and then in that class's destructor call release for the IDirect3DTexture9 interface. Then when the vector goes out of scope in the animation sequence class the COM interfaces would be correctly released because the vector cleanup code would invoke the destructors for the class type of the vector.
    Last edited by VirtualAce; 12-15-2004 at 11:39 AM.

  15. #15
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    Bubba, be careful when creating that "smart pointer" to encapsulate your Texture objects. Anything you put into a vector (or any other STL container) should be copyable, so you would have to have extra handling to know which copy should call Release (assuming calling Release multiple times for the same object is bad). It is a great idea, but you've got to be careful.

    The extra code in your destructor to Release all the Images (which is missing an increment by the way) is necessary no matter what kind of container you use. So while it is a serious memory/resource leak with vectors, the vector part is irrelevent. It is just a serious memory/resource leak with IDirect3DTexture9 objects. You also still do not need clear in that case, although I admit that I have put it in there on occasion myself due to habit.

    As long as people remember that a vector is not smarter about what is inside it than regular arrays or other normal containers, they should be able to remember to do required cleanup.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. vector of vectors containing classes
    By larne in forum C++ Programming
    Replies: 3
    Last Post: 01-13-2009, 07:19 AM
  2. classes and vectors
    By izuael in forum C++ Programming
    Replies: 10
    Last Post: 11-27-2006, 04:19 PM
  3. Vectors and custom classes
    By cunnus88 in forum C++ Programming
    Replies: 16
    Last Post: 05-12-2006, 05:11 AM
  4. vectors and classes
    By jimothygu in forum C++ Programming
    Replies: 3
    Last Post: 04-27-2003, 07:53 PM
  5. How To use vectors for custom classes
    By johnnyd in forum C++ Programming
    Replies: 14
    Last Post: 03-25-2003, 10:04 PM