Доступ к элементам списка объектов производного класса вызывает исключение «нарушение прав чтения», в то время как список заполняется функцией - PullRequest
0 голосов
/ 01 апреля 2019

У меня есть список объектов производных классов 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(); });
}

Я получаю исключение нарушения прав чтения при доступе к элементам списка в лямбде:

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);
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 01 апреля 2019

Вы заполняете список указателями на переменные, локальные для вашей функции FillWithShapes() и хранящиеся в стеке.Их время жизни заканчивается после возврата функции - поэтому разумно, что вы получите нарушение прав доступа.

Когда вы поднимаете код до main(), время жизни локальных переменных теперь равно времени жизни main(),то есть во всей вашей программе и после вашего последнего доступа через список фигур - так что без нарушений.

Возможно, вы захотите прочитать: Что и где находится стек и куча?

1 голос
/ 01 апреля 2019

В вашей функции FillWithShapes вы создаете объекты типа Circle, Sqaure и т. Д. И помещаете эти указатели в вектор. Как только эта функция выходит из области видимости, эти указатели перестают действовать.

Вы можете создавать объекты в куче и помещать их в vector с бременем перераспределения после выполнения с вектором.

...