I was tasked to debug a code that was meant to draw a simple polygon out of 4 points using FLTK. The MyWindow class derive from Fl_Window. The Shape class is the parent class for ClosedPolyline. Both MyWindow and Shape hold a vector to draw all of the shapes.
The problem is that after compiling and run, win.show() opens an empty window without any drawing. I'm puzzled to understand this behavior.
Here is the code (I've omitted some of the parts that are not related to drawing ClosedPolyline):
#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Draw.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Widget.H>
#include <FL/Fl_Device.H>
#include <initializer_list>
#include <vector>
#include <functional>
//#include <cmath>
//#include <math.h>
struct Point {
int x,y;
Point(int xx, int yy) : x(xx), y(yy) { }
};
class Shape{
public:
Point point(int idx) const {
return (points[idx]);
}
unsigned int points_size() const {
return points.size();}
void draw() /*const*/{
draw_lines();
}
void add(Point p){ points.push_back(p); }
protected:
virtual void draw_lines() {}
private:
std::vector<Point> points;
};
class ClosedPolyline: public Shape {
public:
/*ClosedPolyline(std::initializer_list<Point> pp) {
if (pp.size() > 0) {
for (Point p: pp)
add(p);
}
}
*/
ClosedPolyline(Point a1, Point a2, Point a3, Point a4){
add(a1); add(a2); add(a3); add(a4);
}
protected:
void draw_lines() override{
for (unsigned int i=1; i<points_size(); ++i){
fl_line(point(i-1).x, point(i-1).y, point(i).x, point(i).y);
}
}
};
class MyWindow: public Fl_Window {
public:
MyWindow(int x, int y, int w, int h, const char* title = 0)
: Fl_Window(x, y, w, h, title) {}
void Attach(Shape s) {
shapes.push_back(&s);
}
//void draw_shapes(){draw();}
protected:
void draw() override{
for(Shape * s: shapes) {
s->draw();
//s.draw();
}
}
private:
std::vector<Shape*> shapes;
};
And here is the main() function:
int main() {
MyWindow win(100, 100, 600, 400, "C++ Test task");
ClosedPolyline p{Point{100, 100}, Point{100, 200}, Point{500, 100}, Point{500, 200}};
win.Attach(p);
win.end();
win.show();
return (Fl::run());
}
Lets take a look at your MyWindow::Attach function:
void Attach(Shape s) {
shapes.push_back(&s);
}
In the function, the argument s is passed by value. That means it's the same as a local variable inside the function. And as such it will go out of scope and be destructed once the function return.
Saving a pointer to that variable will lead to you saving a stray pointer, pointing to a non-existing object. Dereferencing that pointer will lead to undefined behavior, turning your whole program ill-formed and invalid.
One way to solve the problem is to make sure that the object don't go out of scope. This can be done by using smart pointers like e.g. std::unique_ptr. And to use it from the beginning already when you define the variable p in the main function.
Another way to solve your problem is to assume that the Shape passed to Attach will have a lifetime that outlives the Shape object, and you could therefore pass the Shape by reference:
void Attach(Shape& s) {
shapes.push_back(&s);
}
Now you no longer get a copy of the Shape object, and push a pointer to the original object (in your case the object p in the main function). Dereferencing the pointer will be valid as long as the original object is alive and in scope.
I try run that code in VS2015 and get a lot of error( of course fix attach window pass by reference ) But when I run to linux , it can draw, So I think you should move to linux.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
i saw a few posts with same problem but i didn't not manage to understand how do i make the temporary object to constant
Map.H
#ifndef _Map_
#define _Map_
class Map
{
private:
int Board[7][7];
public:
Map();
Map(int mapNum);
~Map();
void print() const;
};
#endif
Map.Cpp basicly just creates a 7*7 array with 0 or 1 in all places
Robots.H
#ifndef _Robot_
#define _Robot_
#include "Map.h"
class Robot
{
private:
int _RobotID;
int _mapNum;
int _X;
int _Y;
public:
Robot();
~Robot();
Robot (int mapNum, int Line, int Column);
void setRobotID(int newid);
void print() const;
};
#endif
s
Robot.cpp
#include "Robot.h"
#include "Map.h"
#include <iostream>
#include "Game.h"
using namespace std;
Robot::Robot()
{
}
Robot::Robot(int mapNum, int line, int column) {
_mapNum = mapNum;
_X = line;
_Y = column;
_RobotID=0;
}
now creating a map in my main works and so does printing it.
same goes for robot.
what i want to do is connect the robot and the map inside my "game.cpp\game.h" so that each robot that i add will check in the map (double array with 0's or 1's )if it has a 1 it wont add it to map. and if it has a 0 it will.
(addRobot function is suppose to do that)
Game.H
#ifndef _Game_
#define _Game_
#include <vector>
#include <iostream>
#include "Map.h"
#include "Robot.h"
class Game
{
private:
static int _RobotsNum;
Map map1;
Map map2;
public:
void AddRobot(int mapnum, int x, int y);
Map getMap(int mapnum);
Game();
~Game();
};
#endif
Game cpp
#include "Game.h"
#include <algorithm>
#include <vector>
using namespace std;
int Game::_RobotsNum = 0;
vector <Robot> RobotVec;
Game::Game()
: map1(1),
map2(2)
{
}
Game::~Game()
{
}
void Game::AddRobot(int mapnum, int x, int y) {
my main
int main() {
Game game;
// Game* pgame = new Game();
game.AddRobot(1, 3, 4);
game.AddRobot(1, 4, 4);
game.AddRobot(1, 5, 4);
hope you guys can help me. thanks
This constructor has three local variables with the same names as other variables:
Game::Game()
{
vector <Robot> RobotVec; // Not your global variable
Map map1(1); // Not your member variable
Map map2(2); // Not your member variable either
}
In order to initialise members, you use the initialiser list:
Game::Game()
: map1(1),
map2(2)
{
}
In addRobot, this creates a robot and points X at it:
Robot* X = new Robot;
This also creates a robot, so now you have two:
Robot newRobot(mapnum, x, y);
And this memory leak points X away from its original robot and instead points it at newRobot, which will be destroyed immediately afterwards:
X = &newRobot;
Note that addRobot does not at any point add either robot to anything – it creates two and ignores them both.
You should make the vector a member (avoid global variables unless repeating other people's mistakes is a particular passion of yours):
class Game
{
private:
int robotsNum;
vector<Robot> robotVec;
Map map1;
Map map2;
// ...
};
Game::Game()
: robotsNum(0),
map1(1),
map2(2)
{
}
And add your new robot to the vector:
void Game::AddRobot(int mapnum, int x, int y) {
// ...
Robot newRobot(mapnum, x, y);
robotsNum++;
newRobot.setRobotID(robotsNum);
robotVec.push_back(newRobot);
}
Robot newRobot(mapnum, x, y);
This creates an object of type Robot named newRobot. At the end of the block where it was created it will be destroyed.
I am trying to create a program that has the user click twice on the screen and a rectangle is drawn according to what was clicked.
Right now all I am trying to do is set my classes up to be able to correctly draw a rectangle manually without worrying about where the user clicks.
Eventually my program will be able to draw stuff like circles and triangles so I decided to use Polymorphism and have each shape type (i.e. Rectangle) be its own class that inherits from a class called Shapes.
I then have a class called Game which holds a Shapes object.
Shapes.h
#ifndef _shapes_h_
#define _shapes_h_
#include <vector>
#include "glut.h"
class Shapes
{
public:
void DrawAll() const;
void Add(Shapes * shape);
virtual void Draw() const {}
protected:
std::vector<Shapes *> mShapes;
};
#endif
Shapes.cpp
#include "Shapes.h"
#include <iostream>
void Shapes::DrawAll() const
{
int i;
for (i = 0; i < mShapes.size(); i++)
{
mShapes[i]->Draw();
}
}
void Shapes::Add(Shapes * shape)
{
mShapes.push_back(shape);
}
Rectangle.h
#ifndef _rectangle_h_
#define _rectangle_h_
#include "Shapes.h"
class Rectangle : public Shapes
{
public:
Rectangle(std::vector<int> p1, std::vector<int> p2);
void Draw() const;
private:
std::vector<int> mP1;
std::vector<int> mP2;
};
#endif
Rectangle.cpp
#include "Rectangle.h"
#include <iostream>
Rectangle::Rectangle(std::vector<int> p1, std::vector<int> p2)
{
mP1 = p1;
mP2 = p2;
}
void Rectangle::Draw() const
{
std::cout << "Draw Me " << std::endl;
glColor3d(0, 0, 0);
glBegin(GL_QUADS);
glVertex2d(mP1[0], mP1[1]);
glVertex2d(mP2[0], mP1[1]);
glVertex2d(mP2[0], mP2[1]);
glVertex2d(mP1[0], mP2[1]);
glEnd();
}
Game.h
#ifndef _game_h_
#define _game_h_
#include <vector>
#include "Shapes.h"
class Game
{
public:
void Click(int x, int y);
void Draw();
private:
Shapes mTest;
};
#endif
The first Game.cpp below is coded in a way of what I am trying to do, but it throws me the error Unhandled exception at 0x001AF742 in Shapes.exe: 0xC0000005: Access violation reading location 0x00000001. After looking into this, I've found that some __vfptr hidden pointer variable (that I think controls virtual stuff) gets set to 0 and causes memory issues.
Note, Click() only gets called when the mouse is pressed, Draw() is called anytime any type of event happens (e.i. mouse press, mouse release, key press, key release etc.) When the mouse is pressed, both events get called, but Click() gets called first.
Also, mTestis the variable that is the Shapes object.
Game.cpp: Doesn't Work
#include "Game.h"
#include "Rectangle.h"
#include <iostream>
void Game::Click(int x, int y)
{
std::vector<int> p1;
p1.push_back(200);
p1.push_back(200);
std::vector<int> p2;
p2.push_back(250);
p2.push_back(250);
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
mTest.Add(rectangle);
}
void Game::Draw()
{
mTest.DrawAll();
}
However, what seems to baffle me is if I add a Shape Rectangle to mTest inside of the Draw() function right before I call DrawAll(), it works. However, I want to be able to create the Rectangle depending on where the User clicks, and this method wont allow that.
Game.cpp: Works
#include "Game.h"
#include "Rectangle.h"
#include <iostream>
void Game::Click(int x, int y)
{
}
void Game::Draw()
{
std::vector<int> p1;
p1.push_back(200);
p1.push_back(200);
std::vector<int> p2;
p2.push_back(250);
p2.push_back(250);
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
mTest.Add(rectangle);
mTest.DrawAll();
}
In Shapes class replace
std::vector<Shapes *> mShapes;
by
std::vector<std::shared_pointer<Shapes>> mShapes;
Than replace code
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
mTest.Add(rectangle);
by
mTest.Add(std::make_shared<Rectangle>(rp1, rp2));
And finally replace method definition
void Shapes::Add(Shapes * shape)
by
void Shapes::Add(std::shared_ptr<Shapes> shape)
It makes your code works.
Summary: If you need pointers, think about smart pointers (std::unique_ptr mentioned by #user657267 is smart pointer too). You can read about smart pointers in many places, here and here. For better design, do not forget for design patterns.
I'm new to C++, so I decided to work on some little project to improve myself. I try to write a simple chess program with class Unit, and class King which is inherited from Unit
#include <list>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stdlib.h> /* abs */
using namespace std;
// Each unit class represent a chess unit
class Unit{
protected:
int currentX;
int currentY;
string side;
public:
Unit();
Unit(string sideplay, int Xpos,int Ypos)
{
currentX=Xpos; currentY= Ypos;side=sideplay;
}
int getX()
{
return currentX;
}
int getY()
{
return currentY;
}
string getside()
{
return side;
}
void setpos(int newX,int newY) //set new position
{
currentX=newX;
currentY=newY;
}
bool validmove(vector<Unit> unitlist ,string sidepick,int Xpos,int Ypos)
{ int i=0;
while(i != 3)
{ int X=unitlist[i].getX();
int Y=unitlist[i].getY();
string sidetemp= unitlist[i].getside();
if ((X==Xpos)&&(Y==Ypos)&&(sidetemp==sidepick))
{
return false;
}
else if ((X==Xpos)&&(Y==Ypos)&&(sidetemp!=sidepick))
{ //unitlist[i]=NULL;
return true;
}
i++;
}
return true;
}
virtual void moveunit(vector<Unit> unitlist ,int nextX,int nextY);
};
class King: public Unit{
public:
King(string sideplay, int Xpos,int Ypos):Unit(sideplay,Xpos,Ypos)
{}
void moveunit(vector<Unit> unitlist ,int nextX,int nextY){
int diffX=abs(nextX-currentX);
int diffY=abs(nextY-currentY);
if ((diffX==1)||(diffY==1))
{ if (validmove(unitlist,side,nextX,nextY))
{
setpos(nextX,nextY);}
}
}
};
and here is my main:
int main()
{
vector<Unit> chessunit;
chessunit.push_back(King("white",3,1));
chessunit.push_back(King("black",3,2));
chessunit.push_back(King("white",4,1));
if (chessunit[0].validmove(chessunit,"white",3,2))
{
cout<<"hehe"<<endl;
}
chessunit[0].moveunit(chessunit,3,2);
int k= chessunit[0].getY();
cout<<k<<endl;
return 0;
}
I keep getting LNK 2001 error: Unresolved external symbol for my virtual method "moveunit". How can I fix that bug ?
The easiest way of fixing your problem is using pointers or smart pointers: Store vector<Unit*>, vector<std::shared_ptr<Unit>> or vector<std::unique_ptr<Unit>> (thanks #rubenvb) instead of vector<Unit> and then add your kings like so:
myVector.push_back(new King...); // or
myVector.push_back(std::shared_ptr<King>(new King...)); // or
myVector.push_back(std::unique_ptr<King>(new King...));
Why?
If you allocate an object of a virtual class (e.g. Unit unit) and you want to assign an object of an implementation of that class to it, e.g.:
Unit unit;
unit = King(...);
Then you will get an error, or at least run into trouble, unless you provide a constructor for Unit that takes King as an argument or provide a sufficient move operator. That is because if you try to assign an object of a type that is not Unit to unit, the compiler and/or run-time (depending on what the back-end of your compiler is) will have a tough time figuring out how compatible the types are and what to do if things "don't fit" memory-wise and how to cope with memory layout issues.
Further Reading
For more on pointers vs. smart pointers, consider this thread. Also here is a related Stackoverflow question and an article on using shared_ptr with STL collections
More information on trying to "squeeze" an object of one type into another (called slicing) can be found in this thread.
The problem you are facing right now is due to slicing: when you add a King to the vector, it gets sliced into an instance of Unit.
One way to fix this is to turn chessunit into a vector of std::shared_ptr<Unit> and allocate units on the heap.
P.S. Since you are not defining Unit::moveunit(), make it pure virtual:
virtual void moveunit(vector<Unit> unitlist ,int nextX,int nextY) = 0;
^^^
Intro:
In my program, a group object has an std::vector full of polygons (a ring and holes) and a polygon object has an std::vector of points. In reality, the classes are more complicated, I've stripped them down here to illustrate my problem.
The problem:
I want to be able to modify the point's x and y coordinates from within it's corresponding group object. Below, in group.cpp, I have a dummy function called void Group::tryChangingAllX() that tries to accomplish this. However, calling show() on the group afterwards shows no change to it's polygon's point's coordinates.
I think I need to use references/pointers, but I need a nudge in the right direction.
point.cpp:
#include "point.h"
#include <iostream>
Point::~Point(){}
Point::Point(int x, int y){
_x = x;
_y = y;
}
void Point::show(){std::cout << "(" << x() << "," << y() << ")";}
void Point::x(int x){_x = x;}
void Point::y(int y){_y = y;}
int Point::x(){return _x;}
int Point::y(){return _y;}
point.h:
#ifndef POINT_GUARD
#define POINT_GUARD
class Point{
int _x;
int _y;
public:
Point(int x, int y);
~Point();
void show();
int x();
int y();
void x(int x);
void y(int y);
};
#endif
polygon.cpp:
#include "polygon.h"
#include "point.h"
#include <iostream>
#include <vector>
Polygon::~Polygon(){}
Polygon::Polygon(){}
std::vector<Point> Polygon::points(){return _points;}
Polygon::Polygon(std::vector<Point> points){_points = points;}
void Polygon::show(){
std::cout << "Points: ";
for(std::vector<Point>::size_type i = 0; i != _points.size(); i++) {
_points[i].show();
}
}
polygon.h:
#ifndef POLYGON_GUARD
#define POLYGON_GUARD
#include <vector>
#include "point.h"
class Polygon{
//private:
std::vector<Point> _points;
public:
~Polygon();
Polygon ();
Polygon(std::vector<Point> points);
std::vector<Point> points();
void show();
};
#endif
group.cpp:
#include <iostream>
#include <vector>
#include "group.h"
#include "polygon.h"
Group::~Group(){}
Group::Group(std::vector<Polygon> polygons){
_ring = polygons.front();
polygons.erase(polygons.begin());
_holes = polygons;
}
void Group::tryChangingAllX(){
std::vector<Point> points = _ring.points();
for(std::vector<Point>::size_type i = 0; i != points.size(); i++) {
points[i].x(15);
}
}
void Group::show(){
_ring.show();
if(_holes.size()>0){
for(std::vector<Polygon>::size_type i = 0; i != _holes.size(); i++) {
_holes[i].show();
}
}
}
group.h:
#ifndef GROUP_GUARD
#define GROUP_GUARD
#include <vector>
#include "polygon.h"
class Group{
Polygon _ring;
std::vector<Polygon> _holes;
public:
~Group();
Group(std::vector<Polygon> polygons);
void show();
void tryChangingAllX();
};
#endif
Thanks!
The function
std::vector<Point> points();
returns by value, so when you call it, you get a copy of the member. You need to change it to
std::vector<Point>& points();
After you've done this
std::vector<Point> points = _ring.points();
also makes a copy of the returned value. To refer to the actual member in _ring, change to:
std::vector<Point>& points = _ring.points();
That should do it.
Note that you should pass std::vector by const reference to prevent an un-necessary copy:
Polygon(const std::vector<Point>& points);
and consider making methods that don't modify the class const:
int x() const;
This is exactly your problem - you're getting a copy of your points rather than working on a reference to the original points themselves.
polygon.cpp:
return points by reference not value:
std::vector<Point>& Polygon::points(){return _points;} // note the '&' in the return
group.cpp:
obtain a reference to the points, not a copy
std::vector<Point>& points = _ring.points(); // note the '&' in what you're getting
Answers posted by Luchian and lori are technically correct. But there are design considerations that I want to point out.
Returning a reference will allow anyone to modify private parts of Polygon object. By design you only want Group class to do this. Consider making Group a friend of Polygon. Group then will have access to private bits of Polygon. This will ensure a tighter encapsulation overall.
In polygon.h
friend class Group;
In group.cpp
void Group::tryChangingAllX()
{
for(std::vector<Point>::size_type i = 0; i != _ring._points.size(); i++)
{
_ring._points[i].x(15);
}
}
I'm getting a segfault on line 15 of my .cpp file. I'm not sure why. Various code snippets:
explosionhandler.h:
class explosionhandler {
public:
struct explosion {
...
};
vector<struct explosion> explosions;
struct explosion_type {
...
};
vector<struct explosion_type> type;
int num_types;
explosionhandler();
~explosionhandler();
void registerexplosion(int& ttype,ALLEGRO_BITMAP*& b,int seq, float a, float m,float e);
void createexplosion(int ttype,float x,float y);
void drawexplosions(ALLEGRO_BITMAP* screen);
void gettype(explosion_type& a,ALLEGRO_BITMAP*& b,int& nseq, float& aa, float& ee, float& mm);
};#endif
explosionhandler.cpp:
explosionhandler::explosionhandler()
{
num_types=0;
}
void explosionhandler::registerexplosion(int& ttype,ALLEGRO_BITMAP*& b,int seq, float a, float m,float e)
{
explosion_type n;
....
ttype = num_types; /*********** right here *******************/
num_types++;
type.push_back(n);
}
explosionhandler passed as pointer to object rocket:
rocket.h:
...
class explosionhandler;
class rocket {
public:
...
void setrocket(ALLEGRO_BITMAP*& a,ALLEGRO_BITMAP*& b, explosionhandler*& h);
...
int exptype;
...
}; #endif
rocket.cpp:
rocket::rocket()
{
...
exptype=-1;
}
void rocket::setrocket(ALLEGRO_BITMAP*& a,ALLEGRO_BITMAP*& b, explosionhandler*& h)
{
handler = h;
area.sethitboundaries(a);
fprintf(stdout,"setrocket, # of rockets in vector: %i\n",(int)rockets.size());
h->registerexplosion(exptype,b,3,(float)al_get_bitmap_width(b),(float)0,(float)-18); //called function
}
and finally main.cpp (abbreviated):
#include "rocket.h"
#include "explosionhandler.h"
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <stdio.h>
#include <cstdlib>
#define PI 3.14159265
...
rocket rock(bullet_speed+2,width,height);
explosionhandler *handler;
...
int setup()
{
...
rock.setrocket(rk,exp,handler);
rock.setlimit(5);
al_set_target_bitmap(al_get_backbuffer(display));
...
}
...
Ok Yeah its clear now the problem was handler was not initialized. whoops.
and of course explosionhandler is a pointer in main.cpp, rocket is an object declared in main.cpp, both are globals.
Bless my little noob heart I know not what I do.
My psychic sense tells me that you're calling rocket::setrocket with a NULL pointer as the parameter h (or more specifically, a reference to a NULL pointer), and then you're calling h->registerexplosion() on the NULL pointer.
Don't do that. Pass in a valid pointer instead, or allocate a new object (making sure you delete it properly later).