访问派生类对象列表的元素会引发“读访问冲突”异常,而列表则由函数填充

问题描述 投票:0回答:2

我有一个3种类型的派生类对象列表,每个类型包含字符串和两个整数。

#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 ++,所以我不知道在这种情况下会导致这个异常的原因,虽然我可能会遗漏一些简单而重要的东西。


UPD:修复了在堆上创建指针的函数:

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);
        }
    }
}
c++ pointers access-violation derived-class local-variables
2个回答
1
投票

在你的函数FillWithShapes中,你正在创建CircleSqaure等类型的对象并将这些指针推送到向量中。一旦该函数超出范围,这些指针就不再有效。

您可以在堆上创建对象,并在vector中将这些对象推送到使用向量完成后解除分配的负担。


2
投票

您正在填充列表,其中包含指向FillWithShapes()函数本地变量的指针并存储在堆栈中。它们的生命周期在函数返回后结束 - 因此您获得访问冲突是合理的。

当你将代码提升到main()时,局部变量的生命周期现在是main()的生命周期,即整个程序和过去通过形状列表的最后一次访问 - 所以没有违规。

你可能想读:What and where are the stack and heap?

© www.soinside.com 2019 - 2024. All rights reserved.