Hi

This is my first DaniWeb post so I hope I get it right.
My problem is homework. I have almost got it but I'm having trouble with the pointers. The entire program will output svg code but I've tried to leave out as much as I can to reduce the amount of code. There are a number of shape classes, two have been left as stubs. One Svg class and a DataType class. The DataType class has an enumeration of shapes and a union of pointers. This is where I am getting confused. I can't change the way the driver works because code was supplied with the assignment to run the program. I know there is something wrong with the Append functions but I can't work out how to fix them. When I compile, I get the appended rectangles appearing properly above the svg header, then the header, then "89892" which I presume is an address, then the rectangle addresses, then an error "*** glibc detected *** free(): invalid pointer: 0xb7feaff4" then the closing svg tag and the word Aborted.

The output should be: the svg header, then the rectangle tags, then the svg end tag.
Thanks in advance

#include <iomanip>	// output formatting
#include <vector>	// vector class
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;


class Path
{
public:
//stub
}; // Path

class Circle
{
public:
//stub
}; // Circle

class Rectangle
{
public:
    Rectangle();
    Rectangle(int x, int y, int w, int h, string c = "red", string f = "none");
    void Print(ostream & out) const;
private:
    int rx, ry, width, height;
    string colour, fill;
};

ostream & operator<<(ostream & out, const Rectangle & rectangle);


class DataType
{
 public:
  enum { EMPTY, PATH, CIRCLE, RECTANGLE } SVGObj;
  union
  {
    Path *path;
    Circle *circle;
    Rectangle *rectangle;
  };
  DataType();
  DataType(const DataType &);
  DataType(const Circle & obj);
  DataType(const Path & obj);
  DataType(const Rectangle & obj);

  friend istream & operator>>(istream & in, DataType & aDataType);
  friend ostream & operator<<(ostream & out,const DataType & aDataType);
};


struct LNode
{
  DataType data;
  LNode *next;
}*p;

typedef LNode* LNodePtr;


class Svg
{
  public:
    Svg();
    Svg(int w, int h);
    ~Svg(); //destructor
    void SetViewBounds(int minX, int minY);
    void Head(ostream & out) const;
    void Tail(ostream & out) const;
    void Print(ostream & out) const;
    void Append(const DataType & theDataType);
    void Append(const Path & obj);
    void Append(const Circle & obj);
    void Append(const Rectangle & obj);

    friend ostream & operator<<(ostream & out,const Svg & aList);
  private:
    LNodePtr head;
    int size; //size of list

    int myWidth;
    int myHeight;
};


Rectangle::Rectangle()
{
	rx = ry = 0;
	width = height = 64;
	colour = "blue";
	fill = "none";
} // Rectangle


Rectangle::Rectangle(int x, int y, int w, int h, string c, string f)
{
	rx = x;
	ry = y;
	width = w;
	height = h;
	colour = c;
	fill = f;
} // Rectangle


void Rectangle::Print(ostream & out) const
{
  out << "\n<rect x=\"" << rx << "\" y=\"" << ry << "\" width=\"" << width << "\" height=\"" << height
       << "\" stroke-width=\"" << 2 << "\" stroke=\"" << colour << "\" fill=\"" << fill << "\" />" << endl;

} // Rectangle Print


ostream & operator<<(ostream & out, const Rectangle & rectangle)
{
	rectangle.Print( out );
	return out;
} // Rectangle operator<<


// CONSTRUCTOR
DataType::DataType()
{
  SVGObj = EMPTY;
}

DataType::DataType(const DataType & orig)
{
  switch(orig.SVGObj)
  {
  case PATH:
    path = new Path (*orig.path);
    assert(path != NULL);
    break;

  case CIRCLE:
    circle = new Circle (*orig.circle);
    assert(circle != NULL);
    break;

  case RECTANGLE:
    rectangle = new Rectangle (*orig.rectangle);
    assert(rectangle != NULL);
    break;

  case EMPTY:
    break;
  }
  SVGObj = orig.SVGObj;
}

DataType::DataType(const Rectangle & obj)
{
  cout << obj;
}

ostream & operator<<(ostream& out, const DataType& aDataType)
{
 out << aDataType.SVGObj ;
 return out ;
}



//*************Svg member functions *********************
//constructor
Svg::Svg()
{
  head = NULL;
  size = 0;
}

Svg::Svg(int w, int h)
{
  myWidth = w;
  myHeight = h;
}

//destructor
Svg::~Svg()
{
  LNodePtr temp;
  while (head != NULL)
    {
      temp = head;
      head = head-> next;
      delete temp;
    }
  size = 0;
}

void Svg::Head(ostream & out) const	// can't get variable myX to work
// myWidth and myHeight work better than setviewbounds
{
  out << "Svg Head goes here" << endl;
} // svgHead

// XML CLOSING TAG
void Svg::Tail(ostream & out) const
{
  out << "\n</svg>";
} // svgTail


void Svg::Append(const DataType & theDataType) 
{
   LNodePtr temp;
  temp =  new LNode;
  if (temp == 0)
    {
      cerr <<"\n***No more memory!\n";
      exit(1);
    }
  temp->data = theDataType;
  temp->next = NULL;

  if (head == NULL) //empty list
    head = temp;
  else //at least one node
    {
      LNodePtr current = head; 
      //traverse list 
      while (current->next != NULL) 
	current = current->next; 
      //insert node at end of list 
      current->next = temp;
    }
}

void Svg::Append(const Rectangle & obj)
{
   LNodePtr temp;
  temp =  new LNode;
  if (temp == 0)
    {
      cerr <<"\n***No more memory!\n";
      exit(1);
    }
  temp->data = obj;
//  temp->next = NULL;

  if (head == NULL) //empty list
    head = temp;
  else //at least one node
    {
      LNodePtr current = head; 
      //traverse list 
      while (current->next != NULL) 
	current = current->next; 
      //insert node at end of list 
      current->next = temp;
    }
}


ostream & operator<<(ostream & out,const Svg & aList)
{
  LNodePtr temp = aList.head;

  aList.Head(out);
  while(temp != NULL)
  {
    out << temp->data << endl;
    temp = temp->next;
  }
  aList.Tail(out);
  return out;
}


// constants
const int SIZE = 243;           // 3^5 size of the image

// prototypes
void drawSierpinskiCarpet(Svg & graph, int xTL, int yTL, int width, int height);

int main()
{

    Svg carpet( SIZE, SIZE );                           // initialize Svg object
    drawSierpinskiCarpet( carpet, 0, 0, SIZE, SIZE );   // colour the points of Julia set in the rectangl
    cout << carpet; 

  return 0;
}

void drawSierpinskiCarpet(Svg & graph, int xTL, int yTL, int width, int height)
{
    if (width > 2 && height > 2)                    // stop if objects are small
    {
        int w = width/3, h = height/3;              // divide square into 9 sub-squares
        Rectangle rectangle(xTL+w, yTL+h, w, h );   // create the middle rectangle
        graph.Append(rectangle);                    // append to the graph

int i=1;//        for (int i = 0; i < 3; i++)
int j=1;//            for (int j = 0; j < 3; j++)
//                if ( i != 1 || j != 1)              // omit the middle one
                    drawSierpinskiCarpet ( graph, xTL+i*w, yTL+j*h, w, h ); // recursion
    }
} // drawSierpinskiCarpet
Ancient Dragon commented: thanks for using code tags +36

lines 214-218: This will not work because the new operator does not return 0 when memory allocation fails -- it throws an exception. If you want to check for that then you need to use try/catch blocks.

The code you posted is a good example of the MISUSE of unions. If you (or your instructor) had used base class and inherentence then you would not need that DataType structure at all nor would you need all those overloaded methods such as lines 76-79.

As for your actual problem, don't know the answer because we don't have all the code to compile and test.

Hmmm. Maybe you should include the code to make the program run? Also, I would sugguest using inheritance rather than unions for this (like ancient dragon said). Here's the drawer header my school usually uses, which is also our model for learning inheritance, as it demonstrates it quite nicely (as well as some polymorhpism!). I doubt my teacher wants me spreading his code, so I'm only posting the header.

#pragma once

// how long a mutex lock will be attempted before throwing an exception
int const gciMutexTimeout (1000);

#include <windows.h>
#include <process.h>
#include <list>
using namespace std;

//////////////////////////////////////////////////////////////////////////////
// 
// CShape (Base for all shapes)
//
//////////////////////////////////////////////////////////////////////////////
class CShape
{
	friend class CDrawer;

protected:
	int m_iXS;	// start
	int m_iYS;
	int m_iXE;	// end
	int m_iYE;

	// colour for the shape
	COLORREF m_crColour;

	// line thickness
	unsigned int m_uiThick;

public:

	// management
	CShape (COLORREF cr, unsigned int uiThick, int ixs, int iys, int ixe, int iye)
		: m_crColour (cr), m_uiThick (uiThick), m_iXS (ixs), m_iYS (iys), m_iXE (ixe), m_iYE (iye) { }
	virtual ~CShape (void) { }

	// mutators
	void SetThickness (unsigned int uiThick);
	void SetStart (int ix, int iy);
	void SetEnd (int ix, int iy);
	void SetColour (COLORREF crColour);
	void SetColour (unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue);

	// accessors
	COLORREF GetColour (void) const;
	int GetStartX (void) const;
	int GetStartY (void) const;
	int GetEndX (void) const;
	int GetEndY (void) const;

	// operations
	// polymorphic rendering function
	virtual void Render (HDC const & rhdc) const = 0;

	// operator == (Coords Logical)
	bool operator== (CShape const & rSource) const
	{
		if (m_iXE == rSource.m_iXE && m_iXS == rSource.m_iXS &&
			m_iYE == rSource.m_iYE && m_iYS == rSource.m_iYS)
			return true;
		return false;
	}	
};

//////////////////////////////////////////////////////////////////////////////
// 
// CEllipse
//
//////////////////////////////////////////////////////////////////////////////
class CEllipse : public CShape
{
protected:
	COLORREF m_crFillColour;

public:
	CEllipse (int iXS, int iYS, int iXE, int iYE, unsigned int uiThick, COLORREF crLine, COLORREF crFill)
		: CShape (crLine, uiThick, iXS, iYS, iXE, iYE), m_crFillColour (crFill) { }
	
	void SetFillColour (COLORREF crFill) { m_crFillColour = crFill; }
	COLORREF GetFillColour (void) const { return (m_crFillColour); }

	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CRectangle
//
//////////////////////////////////////////////////////////////////////////////
class CRectangle : public CShape
{
protected:
	COLORREF m_crFillColour;

public:
	CRectangle (int iXS, int iYS, int iXE, int iYE, unsigned int uiThick, COLORREF crLine, COLORREF crFill)
		: CShape (crLine, uiThick, iXS, iYS, iXE, iYE), m_crFillColour (crFill) { }
	
	void SetFillColour (COLORREF crFill) { m_crFillColour = crFill; }
	COLORREF GetFillColour (void) const { return (m_crFillColour); }

	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CText
//
//////////////////////////////////////////////////////////////////////////////
class CText : public CShape
{
protected:
	string m_csText;	// if the type for creation was a string

public:
	CText (string csText)
		: CShape (RGB (128, 128, 128), 20, 0, 0, 800, 600), m_csText (csText) { }
	CText (string csText, int iXS, int iYS, int iXE, int iYE, unsigned int uiThick, COLORREF cr)
		: CShape (cr, uiThick, iXS, iYS, iXE, iYE), m_csText (csText) { }
	
	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CWText
//
//////////////////////////////////////////////////////////////////////////////
class CWText : public CShape
{
protected:
	wstring m_csText;	// if the type for creation was a string

public:
	CWText (wstring csText)
		: CShape (RGB (128, 128, 128), 20, 0, 0, 800, 600), m_csText (csText) { }
	CWText (wstring csText, int iXS, int iYS, int iXE, int iYE, unsigned int uiThick, COLORREF cr)
		: CShape (cr, uiThick, iXS, iYS, iXE, iYE), m_csText (csText) { }
	
	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CLine
//
//////////////////////////////////////////////////////////////////////////////
class CLine : public CShape
{
public:
	CLine (int iXS, int iYS, int iXE, int iYE, unsigned int uiThick, COLORREF cr)
		: CShape (cr, uiThick, iXS, iYS, iXE, iYE) { }
	
	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CPoly
//
//////////////////////////////////////////////////////////////////////////////
class CPoly : public CShape
{
	float m_fRotation;
	unsigned int m_uiNumPoints;
public:
	CPoly (int iXS, int iYS, int iSize, float fRotation, unsigned int uiNumPoints, unsigned int uiThick, COLORREF cr)
		: CShape (cr, uiThick, iXS, iYS, iXS + iSize, iYS + iSize), m_fRotation (fRotation), m_uiNumPoints (uiNumPoints) { }
	
	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CInversion
//
//////////////////////////////////////////////////////////////////////////////
class CInversion : public CShape
{
public:
	CInversion (int iXS, int iYS, int iXE, int iYE)
		: CShape (RGB (0, 0, 0), 1, iXS, iYS, iXE, iYE) { }
	
	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CSolidRect
//
//////////////////////////////////////////////////////////////////////////////
class CSolidRect : public CShape
{
protected:
	COLORREF m_crFillColour;

public:
	CSolidRect (int iXS, int iYS, int iXE, int iYE, COLORREF crFill)
		: CShape (RGB (0, 0, 0), 0, iXS, iYS, iXE, iYE), m_crFillColour (crFill) { }
	
	void SetFillColour (COLORREF crFill) { m_crFillColour = crFill; }
	COLORREF GetFillColour (void) const { return (m_crFillColour); }

	virtual void Render (HDC const & rhdc) const;
};

//////////////////////////////////////////////////////////////////////////////
// 
// CDrawer
//
//////////////////////////////////////////////////////////////////////////////
class CDrawer
{
private:
	// no copies or assignment
	CDrawer (CDrawer const & rSource) { }
	CDrawer & operator= (CDrawer const & rSource) { }

protected:
	// windows handle
	static HWND s_hWnd;
	
	// windows procedure callback
	static LRESULT CALLBACK sGDIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

	// the one and only this for the static callback to use
	static CDrawer * s_this;
	
	// flag to indicate if redrawing is required for the window
	static bool s_bRedrawFlag;

	// flag to indicate that the window should take itself out
	static bool s_bExit;

	// mutex handle for thread safety
	static HANDLE s_hListMutex;

	// user backbuffer handle
	static HDC s_hUserBackBuff;

	// user backbuffer bits
	static HBITMAP s_hUserBMBackBits;

	// background colour for the window interior
	static COLORREF s_crBackColour;

	// mouse X and Y pos
	static int s_MouseLPosX;
	static int s_MouseLPosY;
	static int s_MouseRPosX;
	static int s_MouseRPosY;

	// has the mouse position been read?
	static bool s_bMouseLPosRead;
	static bool s_bMouseRPosRead;

	// scale variable
	static int s_iScale;

	// list of lines
	list <CShape *> m_lShapes;

	// message loop thread entry point
	static void mloop (void * pIgnore);

	// deal with mouse click internally
	static void ProcMouseDownL (int iX, int iY);
	static void ProcMouseDownR (int iX, int iY);

public:
	CDrawer(COLORREF crBackgroundColour = RGB (255, 255, 255), int iScale = 1);
	~CDrawer(void);

	// public interface

	// fill passed args with last mouse click pos, return true if new, else false
	static bool GetLastClickLPos (int & riX, int & riY);
	static bool GetLastClickRPos (int & riX, int & riY);
	
	// add a line to the scene
	void AddLine (CLine const & rLine);					
	void AddLine (int iXS, int iYS, int iXE, int iYE, unsigned int uiThick = 1, COLORREF cr = RGB (128, 128, 255));

	// add text to the scene
	void AddText (CText const & rText);	
	void AddText (string csText);
	void AddText (string csText, int iXS, int iYS, int iXE, int iYE, unsigned int uiThick = 1, COLORREF cr = RGB (255, 0, 0));

	// add text to the scene
	void AddWText (CWText const & rText);	
	void AddWText (wstring csText);
	void AddWText (wstring csText, int iXS, int iYS, int iXE, int iYE, unsigned int uiThick = 1, COLORREF cr = RGB (255, 0, 0));

	// add an ellipse to the scene
	void AddEllipse (CEllipse const & rEllipse);		
	void AddEllipse (int iXS, int iYS, int iSize, COLORREF crFill);		
	void AddEllipse (int iXS, int iYS, int iXE, int iYE, unsigned int uiThick, COLORREF crLine = RGB (128, 128, 255), COLORREF crFill = RGB (255, 255, 255));		

	// add a rectangle to the scene
	void AddRectangle (CRectangle const & rRectangle);	
	void AddRectangle (int iXS, int iYS, int iSize, COLORREF crFill);
	void AddRectangle (int iXS, int iYS, int iXE, int iYE, unsigned int uiThick, COLORREF crLine = RGB (128, 128, 255), COLORREF crFill = RGB (255, 255, 255));

	// add an inversion to the scene
	void AddInversion (CInversion const & rInversion);	
	void AddInversion (int iXS, int iYS, int iXE, int iYE);

	// add a solid rect to the scene
	void AddSolidRect (CSolidRect const & rSolidRect);
	void AddSolidRect (int iXS, int iYS, int iSize, COLORREF crFill);
	void AddSolidRect (int iXS, int iYS, int iXE, int iYE, COLORREF crFill);

	void AddPoly (CPoly const & rPoly);
	void AddPoly (int iXS, int iYS, int iSize, float fRotation, unsigned int uiNumPoints, unsigned int uiThick /* = 1 */, COLORREF cr /* = RGB (128, 128, 255) */);
	
	void Render (void);									// render the scene
	void Clear (void);									// clear the scene

	// is the provided point found in any shape(s) (bounding box) in the scene?
	bool IsPointInShapeBounds (int iX, int iY) const;

	// set and get backbuffer pixels directly
	void SetBBPixel (int iX, int iY, COLORREF crColour);
	COLORREF GetBBPixel (int iX, int iY) const;
	
	// reset backbuffer colour to background colour
	void ResetBB (void);
	void ResetBB (COLORREF crNewColour);

	// get front buffer copy as 800 * 600 RGBTRIPLE array on heap, caller must free memory!!!
	RGBTRIPLE * GetFBCopy (void) const;
};

Also, checking to see if the pointer is NULL is a method of checking if the memory was actually allocated. But an exception will halt the execution before this can be checked, so the nothrow arg must be used

ie. pointer = new(nothrow) int;

This is discouraged though, a try/catch is more surefire. But this is a problem that is incredibly rare on modern machines - and running out of memory (not being able to allocate any) would ultimately lead to system issues much bigger than your program executing :P

commented: Exactly :) +36

. But this is a problem that is incredibly rare on modern machines - and running out of memory (not being able to allocate any) would ultimately lead to system issues much bigger than your program executing :P

You are right about that -- the entire computer would just crash and die if that ever happened. For that reason I don't check for allocation failure any more. It was necessary 15 years ago under MS-DOS 6.X and earlier, but not today. Program runs the computer out of memory -- just toss more memory at it :) But that would normally indicate a huge memory leak that needs to be fixed.

I suppose if you were writing software for something with very little available memory (ie a cell phone), it could become a problem. But now I'm just getting off topic.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.