访问派生 class 对象列表的元素抛出 "read access violation" 异常,而列表由函数填充
Accessing elements of derived class object list throws "read access violation" exception, while list is filled by function
我有 3 种类型的派生 class 对象的列表,每种都包含字符串和两个整数。
#include "pch.h"
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <iterator>
class Shape
{
private:
int x, y;
public:
Shape() {}
Shape(int &x_, int &y_) : x(x_), y(y_) {}
virtual void Draw() {
std::cout << this->x << ", " << this->y << "}\n";
}
};
class Circle : public Shape
{
private:
std::string type;
public:
Circle() {}
Circle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Circle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Triangle : public Shape
{
private:
std::string type;
public:
Triangle() {}
Triangle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Triangle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Square : public Shape
{
private:
std::string type;
public:
Square() {}
Square(int &x_, int &y_) : Shape(x_, y_) { this->type = "Square"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle cir;
Triangle tri;
Square sq;
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
cir = Circle(x, y);
ls.push_back(&cir);
}
else if (type == 1) {
tri = Triangle(x, y);
ls.push_back(&tri);
}
else if (type == 2) {
sq = Square(x, y);
ls.push_back(&sq);
}
}
}
int main()
{
std::list<Shape*> shapes;
FillWithShapes(10, shapes);
std::for_each(shapes.begin(), shapes.end(), [](Shape *s) { s->Draw(); });
}
访问 lambda 中的列表元素时出现读取访问冲突异常:
Exception thrown: read access violation.
s->**** was 0xCCCCCCCC.
但是当我将函数 FillWithShapes
的代码直接放到 main()
时,它工作得很好:
Square: {18, 95}
Triangle: {82, 21}
Circle: {2, 53}
Square: {18, 95}
Triangle: {82, 21}
Square: {18, 95}
Circle: {2, 53}
Circle: {2, 53}
Triangle: {82, 21}
Square: {18, 95}
我不久前才开始学习 c++,所以我不知道在这种情况下是什么原因导致了这个异常,尽管我可能在这里遗漏了一些简单但重要的东西。
更新:
修复了在堆上创建指针的函数:
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle *cir = new Circle();
Triangle *tri = new Triangle();
Square *sq = new Square();
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
*cir = Circle(x, y);
ls.push_back(cir);
}
else if (type == 1) {
*tri = Triangle(x, y);
ls.push_back(tri);
}
else if (type == 2) {
*sq = Square(x, y);
ls.push_back(sq);
}
}
}
您正在用指向您的 FillWithShapes()
函数的局部变量并存储在堆栈中的指针填充列表。它们的生命周期在函数 returns 之后结束 - 因此您遇到访问冲突是合理的。
当您将代码提升到 main()
时,局部变量的生命周期现在是 main()
的生命周期,即贯穿您的程序并经过形状列表的最后一次访问 -所以没有违规。
您可能想阅读:What and where are the stack and heap?
在您的函数 FillWithShapes
中,您正在创建 Circle
、Sqaure
等类型的对象并将这些指针推入向量。一旦该函数超出范围,这些指针就不再有效。
您可以在堆上创建对象,然后将对象推送到 vector
中,并在使用向量完成后承担解除分配的负担。
我有 3 种类型的派生 class 对象的列表,每种都包含字符串和两个整数。
#include "pch.h"
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <iterator>
class Shape
{
private:
int x, y;
public:
Shape() {}
Shape(int &x_, int &y_) : x(x_), y(y_) {}
virtual void Draw() {
std::cout << this->x << ", " << this->y << "}\n";
}
};
class Circle : public Shape
{
private:
std::string type;
public:
Circle() {}
Circle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Circle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Triangle : public Shape
{
private:
std::string type;
public:
Triangle() {}
Triangle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Triangle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Square : public Shape
{
private:
std::string type;
public:
Square() {}
Square(int &x_, int &y_) : Shape(x_, y_) { this->type = "Square"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle cir;
Triangle tri;
Square sq;
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
cir = Circle(x, y);
ls.push_back(&cir);
}
else if (type == 1) {
tri = Triangle(x, y);
ls.push_back(&tri);
}
else if (type == 2) {
sq = Square(x, y);
ls.push_back(&sq);
}
}
}
int main()
{
std::list<Shape*> shapes;
FillWithShapes(10, shapes);
std::for_each(shapes.begin(), shapes.end(), [](Shape *s) { s->Draw(); });
}
访问 lambda 中的列表元素时出现读取访问冲突异常:
Exception thrown: read access violation.
s->**** was 0xCCCCCCCC.
但是当我将函数 FillWithShapes
的代码直接放到 main()
时,它工作得很好:
Square: {18, 95}
Triangle: {82, 21}
Circle: {2, 53}
Square: {18, 95}
Triangle: {82, 21}
Square: {18, 95}
Circle: {2, 53}
Circle: {2, 53}
Triangle: {82, 21}
Square: {18, 95}
我不久前才开始学习 c++,所以我不知道在这种情况下是什么原因导致了这个异常,尽管我可能在这里遗漏了一些简单但重要的东西。
更新: 修复了在堆上创建指针的函数:
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle *cir = new Circle();
Triangle *tri = new Triangle();
Square *sq = new Square();
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
*cir = Circle(x, y);
ls.push_back(cir);
}
else if (type == 1) {
*tri = Triangle(x, y);
ls.push_back(tri);
}
else if (type == 2) {
*sq = Square(x, y);
ls.push_back(sq);
}
}
}
您正在用指向您的 FillWithShapes()
函数的局部变量并存储在堆栈中的指针填充列表。它们的生命周期在函数 returns 之后结束 - 因此您遇到访问冲突是合理的。
当您将代码提升到 main()
时,局部变量的生命周期现在是 main()
的生命周期,即贯穿您的程序并经过形状列表的最后一次访问 -所以没有违规。
您可能想阅读:What and where are the stack and heap?
在您的函数 FillWithShapes
中,您正在创建 Circle
、Sqaure
等类型的对象并将这些指针推入向量。一旦该函数超出范围,这些指针就不再有效。
您可以在堆上创建对象,然后将对象推送到 vector
中,并在使用向量完成后承担解除分配的负担。