Thread: 1 constructor, 2 destructor!

  1. #1
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879

    Unhappy 1 constructor, 2 destructor!

    Hey everyone, I'm really stumped on this one. This is my code:
    Code:
    for(i = 0; i < 6; ++i)
    {
    	fighters1.push_back(Ship(false));
    	fighters1[i].init(gfx, (float)i * shipSpace, 1000);
    
    	fighters2.push_back(Ship(false));
    	fighters2[i].init(gfx, (float)(i + 1)  * shipSpace - bmpDimensions.right, 1050 + bmpDimensions.bottom);
    }
    fighters1 and fighters2 are "std::vector<Ship>".
    Somehow, in my log file, this happens:

    Ship constructor
    Ship destructor

    Ship constructor
    Ship destructor

    Ship constructor <- *!
    Ship destructor
    Ship destructor

    Ship constructor <- *!
    Ship destructor
    Ship destructor

    Ship constructor <- *!
    Ship destructor
    Ship destru-*crash*

    Would the constructor/double-destructor have anything to do with using the vector:ush_back()? If anybody needs to see more code, I can post it.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  2. #2
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    I cannot say exaclty what the error is, but I can give you an advice:
    Instead of indexing with [] right after push_back, use vector<>::back() to access the element at the back.

    Btw, why do you have an init() member function instead of a constructor?
    You could have a vector of pointers and code something like this:
    fighters1.push_back(new Ship(gfx, (float)i * shipSpace, 1000));
    Last edited by Sang-drax; 01-31-2003 at 07:20 PM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  3. #3
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    hmm, I guess I should use back(). Probably be clearer what I'm doing, anyways. But the init() is because of this:
    Code:
    Ship ship;
    
    int WINAPI WinMain(...)
    {
         gfx.init(...);
         ship.init(gfx, ...);
    }
    If I were to just use the constructor, I wouldn't be able to declare ship as a global variable, would I? Otherwise, gfx wouldn't be initialized when the ship got declared...?

    p.s. fighters1 and fighters2 are std::vector<Ship>, not std::vector<Ship*>. Would it help if they were vectors of Ship* instead?

    **EDIT**
    I guess I could use an overloaded constructor that calls init(), come to think of it
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  4. #4
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Without seeing how you implemented the class its tricky..

    But at a guess I would say its not "1 Constructor, 2 Destructors" but "1 Constructor,1 Copy Constructor, 2 Destructors".

    With push_back...it constructs an object using the default constructor...then it uses the copy constructor.....

    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std; 
    
    class foobar
    {
    public:
    	foobar(){cout << "Def Constructor" << endl;};
    	foobar(const foobar&){cout << "Copy Constructor" << endl;};
    	~foobar(){cout << "Destructor" << endl;};
    };
    
    int main( void )
    {
    	vector<foobar> v;
    	v.push_back(foobar());
    	v.push_back(foobar());
    	return 0;
    }

  5. #5
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Fordy is correct. Copy constructors are generated automatically if not provided. Try removing the copy constructor from his code.
    You should provide copy constructors to your classes.

    One good way to structure your program is to make an abstract base class called Object and derive different enemies and objects from it.
    Then use a global vector<Obejct*> to hold every object in the game. You can process each object using a virtual method called process() or something.

    If that is too advanced, just turn the vector into vector<Ship*>. That will remove the above problem and decrease overhead.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  6. #6
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Oh, ok Never thought of the copy constructor. I'll try doing the derive-all-from-Object on my next project, but this one is already too complicated and screwed up for me to re-structure it at this point I guess I'll try out the Ship* for the time being, and hope it'll work as a quick-fix... But somehow, I get this evil feeling that it was Ship* before and I changed it to Ship to fix some other bug... Oh well, thanks anyways
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  7. #7
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    I'd say just use Ship* also. Just remember when the vector goes out of scope it won't de-allocate the memory you allocated for the Ship class. You'll have to do it yourself.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  8. #8
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    So, in other words, do this before the vector goes out of scope?
    Code:
    while(fighters1.size() > 0)
    {
        delete fighters1.back();
        fighters1.pop_back();
    }
    while(fighters2.size() > 0)
    {
        delete fighters2.back();
        fighters2.pop_back();
    }
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  9. #9
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Yes.

  10. #10
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Hmm, I guess it doesn't matter at this point, but this work as well?
    Code:
    while(fighters1.size() > 0)
    {
        delete fighters1[0];
        fighters1.erase(&fighters1[0]);
    }
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  11. #11
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Persoanlly I try to avoid stl containers of pointers........it's a pain in the butt to manage memory freeing....Where possible I prefer to use the object itself (and have the container become resoponsible for allocating the memory) or maybe use a basic smartpointer that will ensure the memory is freed when the container's destructor goes

  12. #12
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Too much terminology! lol oh well, I'll copy your post and save it somewhere for later studying
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  13. #13
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    All I'm saying, is that if you need to create objects and store references to them in a container, sometimes its better to forget storing just the references and to allow the container to create the objects

    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class foobar
    {
    public:
    	foobar(){cout << "Def Constructor" << endl;}
    	foobar(const foobar&){cout << "Copy Constructor" << endl;}
    	~foobar(){cout << "Destructor" << endl;}
    };
    
    int main( void )
    {
    	const int nSize = 5;
    	
    	cout << "Create objects inside container" << endl;
    	//create objects inside container
    	vector<foobar> v1(nSize);//make 5 objects	
    	v1.clear();
    	//destruction taken care of
    	
    	cout << "Create objects on stack" << endl;
    	try
    	{
    		foobar* pFoo = 0;
    		vector<foobar*> v2;
    		
    		for(int i = 0;i < nSize;++i)
    		{
    			pFoo = new foobar;
    			v2.push_back(pFoo);
    		}	
    		
    		for(int i = 0;i < nSize;++i)
    		{
    			delete v2[i];
    		}	
    		v2.clear();	
    	
    	}
    	catch(bad_alloc&)
    	{	
    		cout << "Could not alloc memory" << endl;
    	}
    
    
    }
    For instance in the above, you have an extra temporary object being created and destructed when you create the objects using the container.....now for many situations this little ineficiency is worth it because it makes things easier to work with......

    It isnt always possible to do this...maybe you need a container of references?.....maybe you need each object to be constructed differently?....

  14. #14
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Oh, I see. Thanks for the explanation
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Destructor being called on SGI hash_map key
    By cunnus88 in forum C++ Programming
    Replies: 4
    Last Post: 02-11-2009, 12:05 AM
  2. exception in the destructor
    By coletek in forum C++ Programming
    Replies: 3
    Last Post: 01-12-2009, 12:01 PM
  3. Replies: 1
    Last Post: 06-10-2008, 08:38 PM
  4. Destructor inaccessible
    By renanmzmendes in forum C++ Programming
    Replies: 5
    Last Post: 02-19-2008, 11:07 AM
  5. destructor question
    By kocika73 in forum C++ Programming
    Replies: 3
    Last Post: 03-10-2006, 11:29 AM