Thread: Static vector of shared_ptr

  1. #16
    Registered User
    Join Date
    May 2010
    Posts
    178
    Quote Originally Posted by nvoigt View Post
    Can you give a real world example for this? With real classnames so we can maybe suggest a better solution? Right now I don't even know what you are trying to do
    Code:
    #ifndef GRID_H_
    #define GRID_H_
    
    #include<vector>
    #include<memory>
    #include<random>
    #include<ctime>
    
    template <class T> class Grid{
    	static std::vector<std::vector<std::shared_ptr<T>>> cell_grid;
    public:
    	Grid() {
    		
    	        cell_grid = std::vector<std::vector<std::shared_ptr<T>>> 
    			(20, std::vector<std::shared_ptr<T>>(20, nullptr));
    						
    	}
    	virtual ~Grid() {}
    
    };
    
    #endif
    
    #ifndef BUG_H_
    #define BUG_H_
    
    #include "grid.h"
    #include<memory>
    
    class Bug : Grid<Bug>{
    	int x_position, y_position;
    public:
    	Bug() : x_position(0), y_position(0) {}
    	Bug(const int &x_pos, const int &y_pos){
    		this->x_position = x_pos;
    		this->y_position = y_pos;
    	}
    	~Bug() {}
    
    	std::shared_ptr<Bug> factory(const Bug &object){
    
    		return std::shared_ptr<Bug>(new Bug(object));
    	}
    };
    
    #endif
    
    #ifndef ANT_H_
    #define ANT_H_
    
    #include "grid.h"
    #include<memory>
    
    class Ant : Grid<Ant>{
    	int x_position, y_position;
    public:
    	Ant() : x_position(0), y_position(0) {}
    	Ant(const int &x_pos, const int &y_pos){
    		this->x_position = x_pos;
    		this->y_position = y_pos;
    	}
    	~Ant() {}
    
    	std::shared_ptr<Ant> factory(const Ant &object){
    
    		return std::shared_ptr<Ant>(new Ant(object));
    	}
    };
    
    #endif
    This is a real world example of what I would like to do. Grid is the base class, Bug and Ant are the derived classes. Presently, the only compiler problem relates directly and only to the static vector declaration which is what I am trying to solve.

    I am open to class redesign according to best practices.

  2. #17
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    as I understand it, there will be one instance of cell_grid for each template type that is instantiated for that class. basically that means that Grid<Bug>::cell_grid is not the same object as Grid<Ant>::cell_grid. they will be distinct objects in memory.

  3. #18
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    A Bug is not a Grid, so why do you have bug and and derive from grid?

    A grid may reasonable contain bugs and ants, but that's different. All you need is:

    Code:
    class Actor{
      //stuff common to Ants and Bugs
      int x_position, y_position;
    };
    
    
    class Ant : public Actor{...};
    class Bug :  public Actor{...};
    
    
    int main(){
      std::vector<std::vector<std::shared_ptr<Actor>>> cell_grid;
      return 0;
    }
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  4. #19
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    I don't understand why you want to derive your bugs from a grid. Neither an ant nor a bug is a grid. Both can be on a grid if you want. I also don't understand your factory methods that are basically copy constructors. What are they good for? Maybe you can step back a bit from all that design and patterns and tell us what you want to achieve. In plain english
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  5. #20
    Registered User
    Join Date
    May 2010
    Posts
    178
    Quote Originally Posted by nvoigt View Post
    ... Maybe you can step back a bit from all that design and patterns and tell us what you want to achieve. In plain english
    Put smart pointers of (Doodle)Bug and an Ant on a Grid 2D vector that is shared between (Doodle)Bug and Ant.

    I think the previous post has nailed it clearly although I am not certain why I want to define my 2D vector in main rather than in Grid.

  6. #21
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    A grid class could make sense. Just don't make it the same as Actor.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  7. #22
    Registered User
    Join Date
    May 2010
    Posts
    178
    Quote Originally Posted by King Mir View Post
    A grid class could make sense. Just don't make it the same as Actor.
    Thank you. I am still wrapping my mind around class design and have yet to read books on c++ related to good design. Grid won't be the same as Actor and it will not be a templated class either as generics are not needed here.

    Thank you again for pulling my head out of the clouds.

  8. #23
    Registered User
    Join Date
    May 2010
    Posts
    178
    Quote Originally Posted by Imanuel View Post
    Thank you. I am still wrapping my mind around class design and have yet to read books on c++ related to good design. Grid won't be the same as Actor and it will not be a templated class either as generics are not needed here.

    Thank you again for pulling my head out of the clouds.
    I must simply be way out of my league to think I know c++ enough to program this simple project. I posted my code below and I appreciate being notified about my severe shortcomings and gaps in knowledge.

    Code:
    #include<cstdlib>
    #include <memory>
    #include "grid.h"
    
    using namespace std;
    
    int main(int argc, char *argv[]){
    
    	Bug bug(1, 3);
    	Ant ant(1, 2);
    
    	std::shared_ptr<Actor> pbug(new Bug(1, 3));
    	std::shared_ptr<Actor> pant(new Ant(1, 2));
    
    	Grid grid;
    
    	grid.populate(pbug, 1, 3);
    	grid.populate(pant, 1, 2);
    
    	grid.move(pbug);
    
    	return EXIT_SUCCESS;
    }
    
    #ifndef GRID_H_
    #define GRID_H_
    
    #include<vector>
    #include<memory>
    #include<random>
    #include<ctime>
    #include "bug.h"
    #include "ant.h"
    
    class Grid{
    
    	std::vector<std::vector<std::shared_ptr<Actor>>> cell_grid;
    
    	std::vector<std::pair<int, int>> *used_indices;
    
    	bool move_north(std::shared_ptr<Actor> &object){
    		// Move north
    		if(object->get_y_position() - 1 >= 0 && 
    			cell_grid[object->get_x_position()][object->get_y_position() - 1] == nullptr){
    			north_helper(object);
    			return true;
    		}else if (typeid(Ant) == 
    				typeid(cell_grid[object->get_x_position()][object->get_y_position() - 1])){
    			cell_grid[object->get_x_position()][object->get_y_position() - 1].reset();
    			north_helper(object);
    			return true;
    		}else{
    			return false;
    		}
    
    	}
    
    	void north_helper( std::shared_ptr<Actor> & object ) 
    	{
    		object->set_y_position(object->get_y_position() - 1);
    		cell_grid[object->get_x_position()][object->get_y_position()] = object;
    		cell_grid[object->get_x_position()][object->get_y_position() + 1].reset();
    		cell_grid[object->get_x_position()][object->get_y_position() + 1] = nullptr;
    	}
    
    	bool move_east(std::shared_ptr<Actor> &object){
    		// Move east
    		if(object->get_x_position() + 1 <= 19 && 
    			cell_grid[object->get_x_position() + 1][object->get_y_position()] == nullptr){
    				east_helper(object);
    				return true;
    		}else if (typeid(Ant) == 
    			typeid(cell_grid[object->get_x_position() + 1][object->get_y_position()])){
    			cell_grid[object->get_x_position() + 1][object->get_y_position()].reset();
    			east_helper(object);
    			return true;
    		}else{
    			return false;
    		}
    	}
    	void east_helper( std::shared_ptr<Actor> & object ) 
    	{
    		object->set_x_position(object->get_x_position() + 1);
    		cell_grid[object->get_x_position()][object->get_y_position()] = object;
    		cell_grid[object->get_x_position() - 1][object->get_y_position()] = nullptr;
    	}
    
    	bool move_south(std::shared_ptr<Actor> &object){
    		// Move south
    		if(object->get_y_position() + 1 <= 19 && 
    			cell_grid[object->get_x_position()][object->get_y_position() + 1] == nullptr){
    			south_helper(object);
    			return true;
    		}else if(typeid(Ant) == 
    			typeid(cell_grid[object->get_x_position()][object->get_y_position() + 1] )) {
    			cell_grid[object->get_x_position()][object->get_y_position() + 1].reset();
    			south_helper(object);
    			return true;
    		}else{
    			return false;
    		}
    	}
    
    	void south_helper( std::shared_ptr<Actor> & object ) 
    	{
    		object->set_y_position(object->get_y_position() + 1);
    		cell_grid[object->get_x_position()][object->get_y_position()] = object;
    		cell_grid[object->get_x_position()][object->get_y_position() - 1] = nullptr;
    	}
    
    	
    
    	bool move_west(std::shared_ptr<Actor> &object){
    		// Move west
    		if(object->get_x_position() - 1 >= 0 && 
    			cell_grid[object->get_x_position() - 1][object->get_y_position()] == nullptr){
    			west(object);
    			return true;
    		}else if(typeid(Ant) == 
    			typeid(cell_grid[object->get_x_position() - 1][object->get_y_position()])){
    			cell_grid[object->get_x_position() - 1][object->get_y_position()].reset();
    			west(object);
    			return true;
    		}else{
    			return false;
    		}
    	}
    
    	void west( std::shared_ptr<Actor> & object ) 
    	{
    		object->set_x_position(object->get_x_position() - 1);
    		cell_grid[object->get_x_position()][object->get_y_position()] = object;
    		cell_grid[object->get_x_position() + 1][object->get_y_position()] = nullptr;
    	}
    
    	bool random_move_north(std::shared_ptr<Actor> &object){
    		if(move_north(object)){
    			return true;
    		}else if (move_east(object)){
    			return true;
    		}else if(move_south(object)){
    			return true;
    		}else if (move_west(object)){
    			return true;
    		}else{
    			return false;
    		}
    	}
    	bool random_move_east(std::shared_ptr<Actor> &object){
    		if(move_east(object)){
    			return true;
    		}else if (move_south(object)){
    			return true;
    		}else if(move_west(object)){
    			return true;
    		}else if (move_north(object)){
    			return true;
    		}else{
    			return false;
    		}
    
    	}
    	bool random_move_south(std::shared_ptr<Actor> &object){
    		if(move_south(object)){
    			return true;
    		}else if (move_west(object)){
    			return true;
    		}else if(move_north(object)){
    			return true;
    		}else if (move_east(object)){
    			return true;
    		}else{
    			return false;
    		}
    	}
    	bool random_move_west(std::shared_ptr<Actor> &object){
    		if(move_west(object)){
    			return true;
    		}else if (move_north(object)){
    			return true;
    		}else if(move_east(object)){
    			return true;
    		}else if (move_south(object)){
    			return true;
    		}else{
    			return false;
    		}
    	}
    public:
    	Grid() {
    		cell_grid = std::vector<std::vector<std::shared_ptr<Actor>>> 
    						(20, std::vector<std::shared_ptr<Actor>>(20, nullptr));
    
    		used_indices = new std::vector<std::pair<int, int>> (10);
    	}
    	virtual ~Grid() {}
    
    	void populate(std::shared_ptr<Actor> &object, const int &x_pos, const int &y_pos){
    		cell_grid[x_pos][y_pos] = object;
    	}
    
    	bool move(std::shared_ptr<Actor> &object){
    
    		return random_move_north(object);
    		/*
    		srand((unsigned)time(NULL));
    		default_random_engine engine(rand() % 1000);
    		uniform_int_distribution<unsigned> distro(0, 3);
    
    		switch(distro(engine)){
    			case 0: return random_move_north(object);
    			case 1: return random_move_east(object);
    			case 2: return random_move_south(object);
    			case 3: return random_move_west(object);
    			default:
    				return false;
    		}
    		*/
    	}
    };
    
    #endif
    
    #ifndef ACTOR_H_
    #define ACTOR_H_
    
    class Actor{
    	int x_position, y_position;
    public:
    	virtual int get_y_position() const;
    
    	virtual void set_y_position(int val);
    
    	virtual int get_x_position() const;
    
    	virtual void set_x_position(int val);
    };
    
    #endif
    
    #include "actor.h"
    #include<memory>
    
    class Bug : public Actor{
    	int x_position, y_position;
    public:
    	Bug() : x_position(0), y_position(0) {}
    	Bug(const int &x_pos, const int &y_pos){
    		this->x_position = x_pos;
    		this->y_position = y_pos;
    	}
    	~Bug() {}
    
    	int get_y_position() const override { return y_position; }
    
    	void set_y_position(int val) override { y_position = val; }
    
    	int get_x_position() const override { return x_position; }
    
    	void set_x_position(int val) override { x_position = val; }
    };
    
    
    #endif
    
    #ifndef ANT_H_
    #define ANT_H_
    
    #include "actor.h"
    #include<memory>
    
    class Ant : public Actor{
    	int x_position, y_position;
    public:
    	Ant() : x_position(0), y_position(0) {}
    	Ant(const int &x_pos, const int &y_pos){
    		this->x_position = x_pos;
    		this->y_position = y_pos;
    	}
    	~Ant() {}
    
    	int get_y_position() const override { return y_position; }
    
    	void set_y_position(int val) override { y_position = val; }
    
    	int get_x_position() const override { return x_position; }
    
    	void set_x_position(int val) override { x_position = val; }
    };
    
    #endif

  9. #24
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    Your actor class has a position. If you implement it there, you don't need to implement it in your subclasses bug and ant again.

    You Actor has a position, but your grid also saves the position. That's redundant. If one changes, the other might stay the same and you get an inconsistent state. You only need one entity in your model to save the position. Either the grid or the actors.

    Your grid knows about bugs and ants. If there is a certain logic what happens to bugs or ants, maybe it would be better to put it in it's own class and keep the grid agnostic of the rules of play.

    In general, you might want to let us know what you are trying to achieve. In plain normal english. Without code. Because although we might be good coders, we generally suck at telepathy. We don't know what you want. We only see what you tried. And it's hard to suggest better designs without a clue what the goal might be
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  10. #25
    Registered User
    Join Date
    May 2010
    Posts
    178
    Quote Originally Posted by nvoigt View Post
    Your actor class has a position. If you implement it there, you don't need to implement it in your subclasses bug and ant again.

    You Actor has a position, but your grid also saves the position. That's redundant. If one changes, the other might stay the same and you get an inconsistent state. You only need one entity in your model to save the position. Either the grid or the actors.

    Your grid knows about bugs and ants. If there is a certain logic what happens to bugs or ants, maybe it would be better to put it in it's own class and keep the grid agnostic of the rules of play.

    In general, you might want to let us know what you are trying to achieve. In plain normal english. Without code. Because although we might be good coders, we generally suck at telepathy. We don't know what you want. We only see what you tried. And it's hard to suggest better designs without a clue what the goal might be
    I thought I did this a number of times above through the course of this thread.

    What I want: To create a predator/prey simulator. Predators are bugs and the prey are ants. The predators and ants reside on a 2D grid 20 X 20. The predators and prey move randomly. If a predator encounters prey, it eats it. Otherwise they both move according to the same rules. The process of eating removes an ant.

    Specifically: I want to put predators and prey represented as smart pointers onto the 20 X 20 grid. I do not want to store their position on a 2D vector of ints ... I want to put pointers to the bugs and ants on the 2D grid making their movement and removal from the grid easy.

    The process of being eaten is as simple as calling release() on the shared pointer. I thought I was doing this but ran into problems.

    I can not overstate, understate, rearrange, or re-communicate this any more. The info above is just copies of what I wrote previously.

  11. #26
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    If you have a grid of Actors that know about their own location on the grid, then that's redundant information; it means moving an Actor has to update two places. So you should probably not have Actors store their own location, only their age.

    Also, shared_ptr is the wrong smart pointer here. You should use auto_ptr. auto_ptr is generally discouraged because it has weird copy semantics, but they happen to be what you want here. You could also use unique_ptr if you work around the copy semantics.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  12. #27
    Registered User
    Join Date
    May 2010
    Posts
    178
    Quote Originally Posted by King Mir View Post
    If you have a grid of Actors that know about their own location on the grid, then that's redundant information; it means moving an Actor has to update two places. So you should probably not have Actors store their own location, only their age.

    Also, shared_ptr is the wrong smart pointer here. You should use auto_ptr. auto_ptr is generally discouraged because it has weird copy semantics, but they happen to be what you want here. You could also use unique_ptr if you work around the copy semantics.
    I will rework this problem based upon your input. I did read auto_ptr was replaced by a unique_ptr and recommends I should use a unique_ptr which has similar call semantics to shared_ptr but solely owns the object.

    Why do you recommend the use of auto_ptr?

  13. #28
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Because unique_ptr doesn't have a copy assignment operator. You can work around this, but auto_ptr is easier.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  14. #29
    Registered User
    Join Date
    May 2010
    Posts
    178
    Quote Originally Posted by King Mir View Post
    Because unique_ptr doesn't have a copy assignment operator. You can work around this, but auto_ptr is easier.
    I can prob get around no copy or assign of unique_ptr by returning one from a function which the compiler allows just to stay in keeping with current convention.

  15. #30
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    That doesn't help you move actors in the grid.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. std::tr1::shared_ptr question
    By StainedBlue in forum C++ Programming
    Replies: 13
    Last Post: 07-18-2010, 11:48 AM
  2. Replies: 8
    Last Post: 12-30-2008, 02:20 PM
  3. When to use shared_ptr?
    By hpesoj in forum C++ Programming
    Replies: 15
    Last Post: 07-22-2008, 04:33 AM
  4. static vector<...> in class problem.
    By alkis_y3k in forum C++ Programming
    Replies: 5
    Last Post: 01-29-2003, 04:13 PM
  5. vector static abstract data structure in C?
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 11-05-2001, 05:02 PM