我编写了可以生成随机几何图形并以cmd形式以文本形式显示的代码。
这是我的3个文件:
Geometry.h
#pragma once
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#include <iostream>
#include <time.h>
#include <fstream>
#include <string>
#define PI 3.1415926535
using namespace std;
enum color { White, Red, Green, Blue, Yellow, Black };
enum _shape { line, rectangle, circle, picture }; //to roll shapes
void print_color(color c);
//--------------------------Point---------------------------
class Point {
private:
int m_xc, m_yc; //(x,y) coordinats
public:
Point(int x = 0, int y = 0) : m_xc(x), m_yc(y) {}
int x(void) const { return m_xc; };
int y(void) const { return m_yc; };
Point operator+(const Point& p) const
{
return Point(m_xc+p.m_xc, m_yc+p.m_yc);
}
Point& operator+=(const Point& p) //move point
{
m_xc += p.m_xc;
m_yc += p.m_yc;
return *this;
}
friend ostream& operator<<(ostream& os, const Point& p);
Point move(int x, int y){
m_xc += x;
m_yc += y;
return *this;
}
};
//------------------------Shape-----------------------------
class Shape {
protected:
Point m_org;
color m_color;
_shape m_shape;
public:
Shape(const Point& p1 = 0, color c = White, _shape sh = line) : m_org(p1), m_color(c), m_shape(sh){};
virtual ~Shape() = 0 {};
virtual void move(const Point& p) = 0;
virtual void draw(char tabs) const = 0;
virtual void Who_am_I() const = 0;
virtual double Area() const { return 0; };
virtual void Save2File(ofstream &myfile) const = 0;
};
//------------------------Line---------------------------------
class Line : public Shape {
protected:
Point m_end; // line end
public:
Line(const Point& p1, const Point& p2, color c) : Shape(p1, c, line), m_end(p2) {}
void move(const Point& p)
{
m_org += p;
m_end += p;
}
void draw(char tabs) const;
void Who_am_I() const {
print_color(m_color);
cout << "Line";
}
double length() const;
double Area() const { return 0; };
void Save2File(ofstream &myfile) const;
};
//----------------------Rectangle-------------------------------
class Rectangle : public Shape {
protected:
int width;
int height;
public:
Rectangle(const Point& p1, color c = White, int w = 0, int h = 0) : Shape(p1, c, rectangle), width(w), height(h) {}
void move(const Point& p)
{
m_org += p;
}
void draw(char tabs) const;
void Who_am_I() const {
print_color(m_color);
cout << "Rectangle";
}
double Area() const { return width*height; };
void Save2File(ofstream &myfile) const;
};
//----------------------Circle---------------------------
class Circle : public Shape {
protected:
int radius;
public:
Circle(const Point& p1, color c = White, int r = 0) : Shape(p1, c, circle), radius(r) {};
void move(const Point& p)
{
m_org += p;
}
void draw(char tabs) const;
void Who_am_I() const {
print_color(m_color);
cout << "Circle";
}
double Area() const { return PI*(double)radius*(double)radius; };
void Save2File(ofstream &myfile) const;
};
//--------------------------Picture-------------------------
class Picture : public Shape {
private:
Picture(const Picture&); //CCtor is not accessible from main
protected:
Shape** m_shapes; //array of pointers to shapes
int m_count; //number of shapes
static unsigned idx; //number of pictures created for debug
public:
Picture(const Point& p1 = 0, color c = White) : Shape(p1, c, picture), m_count(0){ idx++; }
~Picture();
void insert_shape(Shape* sh);
void draw(char tabs) const;
void move(const Point& p){ m_org += p; };
void Who_am_I() const {
print_color(m_color);
cout << "Picture";
}
void Save2File(ofstream &myfile) const;
int get_count(void){ return m_count; }
double Area() const;
unsigned GetAmPic(void) { return idx; }
};
Geometry.cpp
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#include "geometry.h"
using namespace std;
unsigned Picture::idx = 0;
ostream& operator<<(ostream& os, const Point& p)
{
os << '(' << p.x() << ',' << p.y() << ')';
return os;
}
void print_color(color c) {
string color_print[6] = { "White ", "Red ", "Green ", "Blue ", "Yellow ", "Black " };
cout << color_print[(int)c];
}
//------------------Line methods--------------------
void Line::draw(char tabs) const
{
cout << string(tabs, '\t');
Who_am_I();
cout << " from " << m_org << " to " << m_end << endl;
}
double Line::length() const
{
return sqrt((double)((m_org.x()-m_end.x())*(m_org.x()-m_end.x()) + (m_org.y()-m_end.y())*(m_org.y()-m_end.y())));
}
void Line::Save2File(ofstream& myfile) const {// save to file
myfile << 'L' << " " << m_color << " " << m_org.x() << " " << m_org.y() << " "
<< m_end.x() << " " << m_end.y() << endl;
}
//------------------Rectangle methods----------------
void Rectangle::draw(char tabs) const
{
cout << string(tabs, '\t');
Point temp1 = m_org;
Point temp2 = m_org;
Line l1(temp1, temp2.move(width, 0), m_color);
temp1 = temp2;
Line l2(temp2, temp1.move(0, height), m_color);
temp2 = temp1;
Line l3(temp1, temp2.move(-width, 0), m_color);
temp1 = temp2;
Line l4(temp2, temp1.move(0, -height), m_color);
Who_am_I(); cout << endl;
cout << string(tabs, '\t'); l1.draw(1);
cout << string(tabs, '\t'); l2.draw(1);
cout << string(tabs, '\t'); l3.draw(1);
cout << string(tabs, '\t'); l4.draw(1);
}
void Rectangle::Save2File(ofstream& myfile) const {// save to file
myfile << 'R' << " " << m_color << " " << m_org.x() << " " << m_org.y() << " " << width
<< " " << height << endl;
}
//----------------------Circle methods---------------------------
void Circle::draw(char tabs) const
{
cout << string(tabs, '\t');
Who_am_I();
cout << " Center in " << m_org << " Radius is " << radius << endl;
}
void Circle::Save2File(ofstream& myfile) const {// save to file
myfile << 'C' << " " << m_color << " " << m_org.x() << " " << m_org.y() << " "
<< radius << endl;
}
//----------------------Picture methods--------------------------
void Picture::insert_shape(Shape* s) // insert a new shape to picture
{
if (m_count == 0) {//new picture creating
m_shapes = new Shape*[1];
if (!m_shapes)
cout << "Can't allocate memory!";
}
if (m_count > 0){
Shape** temp = new Shape*[m_count];
memcpy(temp, m_shapes, sizeof(Shape*)*m_count); //save to temp
delete m_shapes; //delete old array
m_shapes = new Shape*[m_count + 1]; //add 1 more place
if (!m_shapes)
cout << "Can't allocate memory!";
memcpy(m_shapes, temp, sizeof(Shape*)*m_count); //return to array
delete temp;
}
m_shapes[m_count] = s; // insert the new shape into the last slot in the array
m_shapes[m_count]->move(m_org); //adjusts the location of the shape
m_count++; // increment the number of shapes in picture
}
void Picture::draw(char tabs) const
{
cout << string(tabs, '\t');
cout << "------------------ ";
Who_am_I();
cout << " ----------------------" << endl;
for (unsigned i = 0; i < m_count; i++)
{
m_shapes[i]->draw(tabs + 1); // draw each shape
}
cout << string(tabs, '\t');
cout << "------------------ End ";
Who_am_I();
cout << " ------------------ " << endl;
}
double Picture::Area() const //sum of areas of all shapes in the picture
{
double area = 0;
for (int i = 0; i < m_count; i++)
{
area += m_shapes[i]->Area();
}
return area;
}
Picture::~Picture()
{
for (int i = 0; i < m_count; i++){
if (m_shapes[i])
delete m_shapes[i];
}
Who_am_I(); cout << " deleting..." << endl;
// sometimes (every 5-10 runs) error here. can't reproduce and debug
if (m_shapes)
delete m_shapes;
// seems like program try to delete already freed memory
}
void Picture::Save2File(ofstream& myfile) const // save to file
{
myfile << 'P' << " " << m_color << " " << m_org.x() << " " << m_org.y() << endl;
for (int i = 0; i < m_count; i++)
m_shapes[i]->Save2File(myfile);
myfile << 'E' << endl; // end of a picture
}
drawing_app.cpp
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#include "geometry.h"
#include <iostream>
#define MAX_PICS_IN_PIC 3
#define MAX_SHAPES 5
using namespace std;
void randomizer(Picture*, int); //recursive function
Picture* Load(istream&);
Point GenP(void);
color GenC(void);
int GenLen(void);
int main(void)
{
srand((unsigned int)time(NULL));
Picture *main_pic = new Picture(Point(0, 0), GenC());
ofstream myfile_write("myfile.txt", ios::out);
if (!myfile_write.is_open())
cout << "Can't open file!" << endl;
randomizer(main_pic, MAX_PICS_IN_PIC); //recursive function
main_pic->Save2File(myfile_write); //save picture to file
myfile_write.close();
cout << " Created Picture:" << endl << endl;
main_pic->draw(0); //draw the main picture
cout << "Created: " << main_pic->GetAmPic() << " pictures." << endl; // for debugging
delete[] main_pic;
ifstream myfile_read("myfile.txt", ios::in);
if (!myfile_read.is_open())
cout << "Can't open file!" << endl;
Picture* buff_pic = Load(myfile_read); //load the picture from the file
cout << endl << endl << " Loaded Picture:" << endl << endl;
buff_pic->draw(0); //display loaded picture
myfile_read.close();
delete[] buff_pic;
cout << "\nLeaks: " << _CrtDumpMemoryLeaks() << endl;
return 0;
}
void randomizer(Picture* pic, int count) {
for (int i = 0; i < MAX_SHAPES; i++){
Point p1 = GenP(); //m_org of the shape
color c = GenC(); //roll random color
_shape shape;
shape = (_shape)(rand() % 4); //roll random shape
if (shape == line){
Point p2 = GenP();
Line* _line = new Line(p1, p2, c);
pic->insert_shape(_line);
}
if (shape == rectangle){
Rectangle* _rect = new Rectangle(p1, c, GenLen(), GenLen());
pic->insert_shape(_rect);
}
if (shape == circle){
Circle* _circ = new Circle(p1, c, GenLen());
pic->insert_shape(_circ);
}
if (shape == picture){
if (count > 0){
Picture* inner_pic = new Picture(p1, c);
count--;
randomizer(inner_pic, count);
pic->insert_shape(inner_pic);
}
else return;
}
}
}
Picture* Load(istream& myfile) {
int m_color, m_org_x, m_org_y;
char m_shape;
myfile >> m_shape >> m_color >> m_org_x >> m_org_y; //read first line
Picture* pic = new Picture(Point(m_org_x, m_org_y), (color)m_color); //create the main picture
myfile >> m_shape; //read next line for shape
while (m_shape != 'E')
{
if (m_shape == 'L'){
int m_end_x, m_end_y;
myfile >> m_color >> m_org_x >> m_org_y >> m_end_x >> m_end_y;
Line* _line = new Line(Point(m_org_x, m_org_y), Point(m_end_x, m_end_y), (color)m_color);
pic->insert_shape(_line);
}
if (m_shape == 'C'){
int radius;
myfile >> m_color >> m_org_x >> m_org_y >> radius;
Circle* Circel = new Circle(Point(m_org_x, m_org_y), (color)m_color, radius);
pic->insert_shape(Circel);
}
if (m_shape == 'R') {
int m_width, m_height;
myfile >> m_color >> m_org_x >> m_org_y >> m_width >> m_height;
Rectangle* Rect = new Rectangle(Point(m_org_x, m_org_y), (color)m_color,
m_width, m_height);
pic->insert_shape(Rect);
}
if (m_shape == 'P') {
myfile.seekg(-1, ios::cur);
Picture* inner_pic = Load(myfile);
pic->insert_shape(inner_pic);
}
myfile >> m_shape;
}
return pic;
}
Point GenP(){ //roll random point x = 0 to 30, y = 0 to 30
Point p(rand() % 31, rand() % 31);
return p;
}
color GenC(){ //generate random color
return (color)(rand() % 6);
}
int GenLen(){ // generate random length from 1 to 50
return rand() % 50 + 1;
}
每5到10次运行,我都会收到一个奇怪的错误:
Geometry.exe中0x5214A9E8(msvcr120d.dll)的未处理异常:0xC0000005:访问冲突读取位置0xCDCDCDC1。
将我引荐到Picture
类的析构函数。我无法重现此错误,也找不到此错误的来源。您有什么想法可以调试吗?
答案 0 :(得分:0)
如果您想用C ++代码调试崩溃,请让我向您展示如何使用和检查转储:
使用以下命令在进程的监视方式下创建转储
ADPlus -Crash -pmn Geometry.exe -o C:\CrashDumps
注意:您可能需要在转储检查中创建/加载符号(.pdb)文件
答案 1 :(得分:0)
一个明显的错误是,完全有可能(而且很容易)尝试在delete
析构函数中m_shapes
一个未初始化的Picture
指针。
您的代码概述如下:
class Picture : public Shape {
private:
Picture(const Picture&); //CCtor is not accessible from main
protected:
Shape** m_shapes; //array of pointers to shapes
int m_count; //number of shapes
static unsigned idx; //number of pictures created for debug
public:
Picture(const Point& p1 = 0, color c = White) : Shape(p1, c, picture), m_count(0){ idx++; }
//...
~Picture();
};
在~Picture()
函数中,您可以执行以下操作:
Picture::~Picture()
{
for (int i = 0; i < m_count; i++){
if (m_shapes[i])
delete m_shapes[i];
}
if (m_shapes) // This may not have been initialized!!
delete m_shapes;
}
在Picture()
构造函数中,您未能初始化m_shapes
,因此,一个简单的单行程序将能够调用未初始化指针上的调用delete
的未定义行为。
示例:
int main()
{
Picture p(Picture(Point(0, 0), GenC()));
} // The `p` destructor will invoke undefined behavior.
因此,立即修复是返回并确保在构造m_shapes
时将nullptr
初始化为(至少)Picture
。
但是,最终的解决方法是除了使用std::vector
和/或std::shared_ptr<Shape>
等智能指针之外,还开始使用std::unique_ptr<Shape>
和其他容器。执行此操作时,诸如Picture::insert_shape
之类的函数要么过时,要么是简单的单行函数,发出对std::vector<Shape*>::push_back()
的调用。
例如(使用原始指针向量)
#include <vector>
class Picture
{
//...
std::vector<Shape *> m_shapes;
void insert_shape(Shape* s);
//...
};
void Picture::insert_shape(Shape* s)
{
m_shapes.push_back(s);
}
答案 2 :(得分:0)
此行中有错误。
Picture *main_pic = new Picture(Point(0, 0), GenC());
您没有给图片指针指定大小,而是像数组一样将其删除。您必须为指针分配大小,然后也可以像这样删除。
delete [] main_pic;