Jump to content

  • Log In with Google      Sign In   
  • Create Account

Can you create a Vector of structs in C++? I need help with a unknown error pertaining to this subject.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
22 replies to this topic

#1 black_darkness   Members   -  Reputation: 280

Like
0Likes
Like

Posted 11 December 2012 - 08:56 PM

I am painting 64 squares onto a screen using Fast Light ToolKit. In order to save time I created a loop to do this automatically. Since I need to dynamically create new objects I decided to push the struct Rectangle into a vector. However when I run the program I get a single error.
error C2248: 'Graph_lib::Shape::Shape' : cannot access private member declared in class 'Graph_lib::Shape'


Here is the main loop
int main()
{
Point tl(100,100); //top left corner of window
Simple_window win(tl,400,400,"My Window");
vector<Rectanglee> rects; //Here is where I think the problem lies.

for (int i=0;i<8;i++){
  int xa=(i*50)-1;
  for(int j=0;j<8;j++){
   int ya=(j*50)-1;
   Rectanglee rect(Point(i,j),50,50);
   rects.push_back(rect);
  }
}
for(int i=0;i<64;i++){
  win.attach(rects[i]); //attach rect to screen
}
win.wait_for_button(); //wait until user clicks the next button to close window
}



Here is the rectanglee struct.
struct Rectanglee : Shape {
    Rectanglee(Point xy, int ww, int hh) : w(ww), h(hh)
    {
	    add(xy);
	    if (h<=0 || w<=0) error("Bad rectangle: non-positive side");
    }
    Rectanglee(Point x, Point y) : w(y.x-x.x), h(y.y-x.y)
    {
	    add(x);
	    if (h<=0 || w<=0) error("Bad rectangle: non-positive width or height");
    }
    void draw_lines() const;
    int height() const { return h; }
    int width() const { return w; }
private:
    int h;    // height
    int w;    // width
};


Sponsor:

#2 Hodgman   Moderators   -  Reputation: 30341

Like
3Likes
Like

Posted 11 December 2012 - 09:16 PM

That error says that the Shape constructor is private. Can you post the code for Shape?

#3 black_darkness   Members   -  Reputation: 280

Like
0Likes
Like

Posted 11 December 2012 - 09:20 PM

That error says that the Shape constructor is private. Can you post the code for Shape?


Yes.

Here are the headers I am using http://www.stroustrup.com/Programming/Graphics/ . The shape is in the graph.h file I think.


Anyways here is the Shape class.
class Shape  {	    // deals with color and style, and holds sequence of lines
public:
    void draw() const;				 // deal with color and draw lines
    virtual void move(int dx, int dy); // move the shape +=dx and +=dy
    void set_color(Color col) { lcolor = col; }
    Color color() const { return lcolor; }
    void set_style(Line_style sty) { ls = sty; }
    Line_style style() const { return ls; }
    void set_fill_color(Color col) { fcolor = col; }
    Color fill_color() const { return fcolor; }
    Point point(int i) const { return points[i]; } // read only access to points
    int number_of_points() const { return int(points.size()); }
    virtual ~Shape() { }
protected:
    Shape();   
    virtual void draw_lines() const;   // draw the appropriate lines
    void add(Point p);				 // add p to points
    void set_point(int i,Point p);	 // points[i]=p;
private:
    vector<Point> points;			  // not used by all shapes
    Color lcolor;					  // color for lines and characters
    Line_style ls;
    Color fcolor;					  // fill color
    Shape(const Shape&);			   // prevent copying
    Shape& operator=(const Shape&);
};

Edited by black_darkness, 11 December 2012 - 09:23 PM.


#4 SiCrane   Moderators   -  Reputation: 9593

Like
5Likes
Like

Posted 11 December 2012 - 09:32 PM

Shape isn't copyable, so any derived classes are also not copyable and you can only stick copyable objects in a vector. You could try a vector of (smart) pointers instead.

#5 Álvaro   Crossbones+   -  Reputation: 13291

Like
4Likes
Like

Posted 11 December 2012 - 09:33 PM

It looks like whoever wrote Shape didn't want them to be copied, but you are making a vector of Rentanglees, which implies copying them around, and the copy constructor for Rectanglee tries to invoke the copy constructor for Shape.

EDIT: Ninja'd.

Edited by Álvaro, 11 December 2012 - 09:33 PM.


#6 black_darkness   Members   -  Reputation: 280

Like
0Likes
Like

Posted 11 December 2012 - 09:38 PM

Okay. Thanks for the help. Posted Image

#7 uglybdavis   Members   -  Reputation: 918

Like
2Likes
Like

Posted 11 December 2012 - 09:43 PM

May i suggest (read the comments, i changed them:

[source lang="cpp"]int main() {Point tl(100,100); Simple_window win(tl,400,400,"My Window");vector<Rectanglee*> rects; // Pointer Magic! for (int i=0;i<8;i++){ int xa=(i*50)-1; for(int j=0;j<8;j++){ int ya=(j*50)-1; rects.push_back(new Point(i,j),50,50); }}for(int i=0;i<64;i++){ win.attach(*(rects[i])); //Remember to de-reference}win.wait_for_button(); //wait until user clicks the next button to close window// Clean up at some point!for (unsigned int i = 0, size = rects.size(); i < size; ++i) delete rects[i];}[/source]

#8 Cornstalks   Crossbones+   -  Reputation: 6985

Like
3Likes
Like

Posted 11 December 2012 - 09:50 PM

May i suggest (read the comments, i changed them:
*snip*


FYI, putting raw pointers into a container like vector like that is a fantastic way to introduce memory leaks, double deletes, etc. Best use a smart pointer.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#9 CatmanFS   Members   -  Reputation: 187

Like
0Likes
Like

Posted 12 December 2012 - 12:59 AM

vector <int*> names; works, so then wouldn't you have a vector of structs or classes if the int* referred to the addresses in memory of different data structs?

#10 BitMaster   Crossbones+   -  Reputation: 4070

Like
3Likes
Like

Posted 12 December 2012 - 01:39 AM

vector <int*> names; works, so then wouldn't you have a vector of structs or classes if the int* referred to the addresses in memory of different data structs?


For the reasons above having raw pointers to Rectanglee in the vector is generally not a good idea unless you have the experience to know what you are really doing (and if the OP is confused by a private copy constructor then he is definitely not there). Dropping all type safetype by forcing a cast from int* to Rectanglee* is much, much worse for absolutely no benefit. You lose all type safety and gain exactly nothing over the Rectanglee* implementation. You also have the option of walking well off into undefined behavior if you do not understand the casts between the involved pointers very well and depending on how your inheritance hierarchy looks. And you still have to allocate storage for the Rectanglee somewhere somehow for the pointers to point to.

Even setting those things aside, why would you store int* instead of Rectanglee*? If something like that has to be done (and I cannot imagine any reason out of the top of my head that is not done better by other methods), why not use at least void*?

That said, the obvious candidate to solve the issues is boost::shared_ptr. In C++11 either std::shared_ptr or std::unique_ptr would do the job. Of course if we had C++11 I would rather make the involved type movable and just stick them into containers normally (if possible).

#11 rnlf   Members   -  Reputation: 1119

Like
2Likes
Like

Posted 12 December 2012 - 01:40 AM

CatmanFS: Not quite sure, what you mean, but if you want to have a vector<int*>'s element point to instances of anything different than ints, you will have to use an explicit cast. This will work maybe, but is more or less one of the most evil things to do.

Also, as Cornstalks already said, using raw pointers instead of smart pointer creates a lot of potential problems later on.

Edit: you ninja, BitMaster

Edited by rnlf, 12 December 2012 - 01:41 AM.

my blog (German)


#12 black_darkness   Members   -  Reputation: 280

Like
0Likes
Like

Posted 12 December 2012 - 11:20 AM

May i suggest (read the comments, i changed them:

[source lang="cpp"]int main() {Point tl(100,100);Simple_window win(tl,400,400,"My Window");vector<Rectanglee*> rects; // Pointer Magic!for (int i=0;i<8;i++){ int xa=(i*50)-1; for(int j=0;j<8;j++){ int ya=(j*50)-1; rects.push_back(new Point(i,j),50,50); }}for(int i=0;i<64;i++){ win.attach(*(rects[i])); //Remember to de-reference}win.wait_for_button(); //wait until user clicks the next button to close window// Clean up at some point!for (unsigned int i = 0, size = rects.size(); i < size; ++i) delete rects[i];}[/source]


I read this article http://www.cplusplus...orial/pointers/ . And from what I understand making rects a pointer would make it incapable of using push_back which is the whole reason I am using a vector in the first place.

I suppose if I did something like this. It might work.

for (int i=0;i<8;i++){
  int xa=(i*50)-1;
  for(int j=0;j<8;j++){
   int ya=(j*50)-1;
   (*rects).push_back(new Point(i,j),50,50);
  }
}

Edited by black_darkness, 12 December 2012 - 11:26 AM.


#13 SiCrane   Moderators   -  Reputation: 9593

Like
0Likes
Like

Posted 12 December 2012 - 11:25 AM

Don't make rects a pointer, make it a vector containing pointers. Preferably smart pointers, but regular pointers would also work. Either way it's legal to store both regular and smart pointers inside a vector, including using push_back().

#14 black_darkness   Members   -  Reputation: 280

Like
0Likes
Like

Posted 12 December 2012 - 11:30 AM

Don't make rects a pointer, make it a vector containing pointers. Preferably smart pointers, but regular pointers would also work. Either way it's legal to store both regular and smart pointers inside a vector, including using push_back().


So something like this. I have never used smart pointers. But I will look into it.

for (int i=0;i<8;i++){
  int xa=(i*50)-1;
  for(int j=0;j<8;j++){
   int ya=(j*50)-1;
   Rectanglee rect(Point(i,j),50,50);
   rects.push_back(&rect);
  }
}

Edited by black_darkness, 12 December 2012 - 11:30 AM.


#15 SiCrane   Moderators   -  Reputation: 9593

Like
0Likes
Like

Posted 12 December 2012 - 11:32 AM

You shouldn't store a pointer to an object on the stack in a vector. Use new to create your object and store that pointer instead.

#16 kunos   Crossbones+   -  Reputation: 2207

Like
0Likes
Like

Posted 12 December 2012 - 11:34 AM


Don't make rects a pointer, make it a vector containing pointers. Preferably smart pointers, but regular pointers would also work. Either way it's legal to store both regular and smart pointers inside a vector, including using push_back().


So something like this. I have never used smart pointers. But I will look into it.

for (int i=0;i<8;i++){
  int xa=(i*50)-1;
  for(int j=0;j<8;j++){
   int ya=(j*50)-1;
   Rectanglee rect(Point(i,j),50,50);
   rects.push_back(&rect);
  }
}


that is a crash man. You cannot grab the address of a stack variable like that just as you cannot return a pointer to a variable declared into a function. Once it goes out of scope you'll be pointing at garbage memory.

rects.push_back(new Rectangle(bbla bla bla));
Stefano Casillo
Lead Programmer
TWITTER: @KunosStefano
AssettoCorsa - netKar PRO - Kunos Simulazioni

#17 black_darkness   Members   -  Reputation: 280

Like
0Likes
Like

Posted 12 December 2012 - 12:07 PM



Don't make rects a pointer, make it a vector containing pointers. Preferably smart pointers, but regular pointers would also work. Either way it's legal to store both regular and smart pointers inside a vector, including using push_back().


So something like this. I have never used smart pointers. But I will look into it.

for (int i=0;i<8;i++){
  int xa=(i*50)-1;
  for(int j=0;j<8;j++){
   int ya=(j*50)-1;
   Rectanglee rect(Point(i,j),50,50);
   rects.push_back(&rect);
  }
}


that is a crash man. You cannot grab the address of a stack variable like that just as you cannot return a pointer to a variable declared into a function. Once it goes out of scope you'll be pointing at garbage memory.

rects.push_back(new Rectangle(bbla bla bla));



I tried that, but it says Rectanglee has no default constructor. I can see now that this problem is too advanced for me. I give up now. Thanks for the help.

#18 uglybdavis   Members   -  Reputation: 918

Like
-1Likes
Like

Posted 12 December 2012 - 12:12 PM

@black_darkness

[source lang="cpp"]vector<SomeData>* pVector; // Pointer to a vectorpVector = new Vector<SomeData(); // Make new vectorpVector->push_back(something);(*pVector).push_back(something);delete pVector; // Delete the vectorsvector<SomeData*> Vector; // Vector storing pointersVector.push_back(new SoemData()); // Make new datadelete Vector[0]; // Delete the elementsvector<SomeData*>* pVector; // Vector pointer to pointerspVector = new vector<SomeData*>(); // Make the data structurepVector->push_back(new SomeData()); // Make new data(*pVector).push_back(new SomeData()); // Just syntax differencedelete pVector[0]; // Delete elements firstdelete pVector[1]; // We added two elementsdelete pVector; // Delete the vector[/source]

Seems like you are confused about what a vector is / how memory is managed. Also seems that you don't fully understand what the stack / heap are. The beauty of C++ is that YOU are responsible for the memory. Forget about all the fancy smart pointer work, you use C++ in games for the speed, don't add overhead. Learn how to manage your memory. Seriously, learn memory management it's a very important skill.

Does the code sample above shed some light as to what's going on?

Edited by uglybdavis, 12 December 2012 - 12:14 PM.


#19 kunos   Crossbones+   -  Reputation: 2207

Like
0Likes
Like

Posted 12 December 2012 - 12:13 PM

i think you forgot the "bbla bla bla" part Posted Image

There you go:

vector<Rectangle*> rects;

rects.push_back(new Rectangle(Point(i,j),50,50));

This will work.. but I agree with you, it's a good thing for you to step back and get more familiar with C++ .
Stefano Casillo
Lead Programmer
TWITTER: @KunosStefano
AssettoCorsa - netKar PRO - Kunos Simulazioni

#20 black_darkness   Members   -  Reputation: 280

Like
0Likes
Like

Posted 12 December 2012 - 12:24 PM

@black_darkness

[source lang="cpp"]vector<SomeData>* pVector; // Pointer to a vectorpVector = new Vector<SomeData(); // Make new vectorpVector->push_back(something);(*pVector).push_back(something);delete pVector; // Delete the vectorsvector<SomeData*> Vector; // Vector storing pointersVector.push_back(new SoemData()); // Make new datadelete Vector[0]; // Delete the elementsvector<SomeData*>* pVector; // Vector pointer to pointerspVector = new vector<SomeData*>(); // Make the data structurepVector->push_back(new SomeData()); // Make new data(*pVector).push_back(new SomeData()); // Just syntax differencedelete pVector[0]; // Delete elements firstdelete pVector[1]; // We added two elementsdelete pVector; // Delete the vector[/source]

Seems like you are confused about what a vector is / how memory is managed. Also seems that you don't fully understand what the stack / heap are. The beauty of C++ is that YOU are responsible for the memory. Forget about all the fancy smart pointer work, you use C++ in games for the speed, don't add overhead. Learn how to manage your memory. Seriously, learn memory management it's a very important skill.

Does the code sample above shed some light as to what's going on?


At this moment no. That probably has to do with a head-ache I have at the moment. I will come back to this thread and post when the head-ache goes away. Thanks for the help and excuse me for all the trouble.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS