Thread: vector contents mysteriously vanishing

  1. #1
    Registered User
    Join Date
    Mar 2006
    Posts
    40

    vector contents mysteriously vanishing

    For a class I have, it uses a vector to keep track of objects that are "in" it. I've recently restructured my code, and it is now broken. It does not keep track of objects correctly.

    Everything appears to be fine, and most of debug statements I added check out.
    Code:
    unsigned short int atom_id = 0, room_id = 0, person_id = 0, item_id = 0;
    
    class atom
    {
      public:
      unsigned short int id, type;
      atom *loc;
      vector<atom> contents;  //This is the vector in question.
      atom()
      {
        type = ATOM; id = atom_id++;
      }
      atom(const atom& A)
      {
      }
      ~atom(){}                         
      friend bool operator==(const atom& lhs, const atom& rhs)
      {
        cout << "Testing("<<lhs.type<<','<<lhs.id<<")("<<rhs.type<<','<<rhs.id<<")\n";
        if(lhs.type != rhs.type) {return false;}
        return (lhs.id==rhs.id);
      }
      virtual void look(void){}
      void entered(atom *A)
      {
        cout <<A->name<<" entering "<<name<<","<<id;
        A->loc = this;
        cout << contents.size();
        contents.push_back(*A);
        cout << A->name << contents.size() << contents[0].name;
      }
      void exitted(atom *A)
      {
        cout << A->name<<" exitting "<<name;
        vector<atom>::iterator index;
        for(index = contents.begin(); index <= contents.end(); index++)
        {
          if(*index == *A)
          {contents.erase(index);}
        }
      }
    };
    class room: public atom
    {
      public:
      room(void) : atom(*this)
      {
        type = ROOM; id = room_id++;
      }
    };
    As you can see, I have 3 debug lines in entered. The first at the beginning tells you that the parameter is trying to enter the source object and gives its ID number. The second just lists the size of the contents vector before it is added to. The third at the end lists the name, new vector size, and the name again as referenced by the vector as per contents[0].

    When I add an object to room by calling entered and passing the object to it, the debug statement at the end of entered, it does not read the name from the vector. It is as if there is no name there to be had.

    Then, when I call enter and pass another object to it, it says again that there are 0 elements to contents before added then 1 after.

    I am not adding or subtracting to/from the vector anywhere else, and exitted is not being called either.

    How can the vector be spontaneously dropping elements?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Are you trying to create some sort of reference counting smart pointer?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Feb 2006
    Posts
    155
    >cout <<A->name
    theres no name.

    and each object of class atom that u create will have a seperate copy of vector<atom>,so its length will be 1 .

    >For a class I have, it uses a vector to keep track of objects that are "in" it.

    a class doesnt have objects in it.

  4. #4
    Registered User
    Join Date
    Mar 2006
    Posts
    40
    (edit)
    I just made the contents vector a vector of atom pointers rather than atom references, and that at least ends up outputting contents[0]->name. It appears to at least be adding the things.

    And now I just changed other things to pointers too, since that worked, and it all works fine now. -.-

    What's the deal, why doesn't it like references to objects, only pointers that end up needing to be dereferenced back to the the object reference anyway?

    You can safely ignore the following. I left it only to answer the questions qqqqxxxx and laserlight asked of me.
    (/edit)

    Quote Originally Posted by qqqqxxxx
    >cout <<A->name
    theres no name.
    But that's the thing, A does have a name, and that part there shows it. It's just the contents[0].name part that shows nothing.
    and each object of class atom that u create will have a seperate copy of vector<atom>,so its length will be 1 .
    I want each object of class atom to have its own copy of the vector. I want each one to be able to keep track of its own contents.

    As for it starting at size 1, why then does the cout<<contents.size() part before the contents.push_back output 0?
    >For a class I have, it uses a vector to keep track of objects that are "in" it.

    a class doesnt have objects in it.
    Hence my quotes around the word in. It is "in" it for my purposes; that is, from the program user's point of view. atom has classes room, person and item derived from it, and any room might contain people, items or even other rooms, and persons/items might contain other persons/items. That is what this contents vector is for, to keep track of what objects are in what other objects according to my setup.

    Quote Originally Posted by laserlight
    Are you trying to create some sort of reference counting smart pointer?
    If I understand your question correctly (which I might not), I don't think so.

    As I said in reply to qqqqxxxx, from the program user's perspective there are rooms, people and items making up a small world. These people can move around between the rooms, pick up or leave behind the items, and so on. A person in a certain room is in that room's contents vector and has its loc variable set to that room, and items in a room or person are in that room or person's contents vector. In fact, any atom can theoretically be inside any other atom according to this setup, though obviously I won't put rooms inside people or items.

    atom.entered(A) is supposed to move A into atom, that is, have A.loc set to "this" and A added to contents.

    And that is where the problem is occuring. When adding the object to the contents vector via contents.push_back(*A), shouldn't that make contents[0] (or whatever is next line, but directly after the push_back line 0 should always be viable) equal *A, and therefor have contents[0].name equal the same thing as A->name? Yet it doesn't show a name for the contents[0].name, and then when I add another object to the same room (my personal person object), the debug output shows contents.size() to be 0 and then 1 again, and shows the name for A->name but not contents[0].name again.

    So it's as if the references of the contents vector are being ignored.
    Last edited by Loduwijk; 03-24-2006 at 10:09 AM.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    My suggestion is to have each atom point to its location, and have a vector of pointers to atoms that are located in it. Have an enterLocation() member function that takes a reference to the new location. Have a leaveLocation() member function that removes itself from its record in its location atom, and then sets itself to a null location. When the atom is destroyed, ensure that it makes its contents leave, and then leaves its own location.

    For example:
    Code:
    #include <algorithm>
    #include <set>
    
    class Atom
    {
    public:
    	Atom() : loc_(0) {}
    	virtual ~Atom()
    	{
    		// force contents to leave
    		std::for_each(contents_.begin(), contents_.end(), makeVagabond);
    		// now this atom leaves its own location
    		leaveLocation();
    	}
    	friend void makeVagabond(Atom* x)
    	{
    		x->loc_ = 0; // a vagabond has no location
    	}
    	void enterLocation(Atom& x)
    	{
    		// leave previous location
    		leaveLocation();
    		// enter new location
    		loc_ = &x;
    		// record its entry in new location
    		x.contents_.insert(this);
    	}
    	void leaveLocation()
    	{
    		// leave location if it not a vagabond
    		if (loc_)
    		{
    			// remove record of entry at old location
    			loc_->contents_.erase(loc_->contents_.find(this));
    			makeVagabond(this);
    		}
    	}
    private:
    	Atom* loc_; // current location
    	std::set<Atom*> contents_; // entries of atoms located in this atom
    };
    
    class Room : public Atom
    {
    	// ...
    };
    EDIT: I changed std::vector to std::set in view that a set might be more appropriate. It is your choice it in end, since only you know what's happening best.
    Last edited by laserlight; 03-24-2006 at 11:59 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    The exitted code in the original post is wrong. When you erase from a vector it invalidates the iterator. The following is the normal way of erasing some items from a vector in a loop:
    Code:
        vector<atom>::iterator index = contents.begin();
        while (index != contents.end())
        {
          if(*index == *A)
          {index = contents.erase(index);}
          else
          {++index;}
        }
    Note the use of != instead of <= (important!), the user of ++index instead of index++ (not that important), and the assigning of the iterator to the return value of erase instead of incrementing it when you erase something (very important!).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Vanishing Doubles
    By EvilGuru in forum C Programming
    Replies: 1
    Last Post: 10-31-2005, 08:05 AM
  2. String is getting mysteriously knackered
    By kzar in forum C Programming
    Replies: 2
    Last Post: 04-10-2005, 08:02 AM
  3. Help with vanishing screen
    By csmatheng in forum Game Programming
    Replies: 6
    Last Post: 05-01-2004, 12:32 AM
  4. disk space mysteriously gone
    By evader in forum C++ Programming
    Replies: 4
    Last Post: 01-21-2004, 01:30 PM
  5. hard drive is mysteriously filling up.
    By Will in forum Tech Board
    Replies: 11
    Last Post: 11-25-2002, 08:03 PM