С ++ прохождение ptrs

У меня все еще много проблем с захватом указателей, я пытался их не использовать, но я не уверен, как лучше всего выполнить следующее.

У меня два класса Point а также RayЯ также уверен, что где-то уже есть реализация класса точек, который я должен использовать вместо этого. Итак, у меня есть эти два класса, и я пытаюсь создать луч и в конечном итоге передать его чему-то другому, но я получаю ошибку: Thread: EXC_BAD_ACCESS (code = 1, address = 0x0) `когда я создаю луч так, как я это делаю, и пытаюсь получить к нему доступ.

class Point {
    public:
    float x;
    float y;
    Point();
    Point(float x, float y);
    ~Point();
};

Point::Point() {
    x = 0;
    y = 0;
}

Point::Point(float xPos, float yPos) {
    x = xPos;
    y = yPos;
    std::cout << "point created at: " << x << ", " << y << std::endl;
}

Point::~Point() {
    std::cout << "point destroyed" << std::endl;
}

class Ray {
public:

    std::unique_ptr<Point> origin;

    float angleInRadians;
    float length;

    float slope();
    Point* pointAtDistance(float percentage);
    Point* pointAtYPos(float yPos);

    Ray(Point& origin, float angleInRadians, float length);
    ~Ray();
};

Ray::Ray(Point& origin, float angleInRadians, float length) {
    origin = std::move(origin);
    angleInRadians = angleInRadians;
    length = length;
}

float Ray::slope() {
    return tanf(angleInRadians);
}

Point* Ray::pointAtDistance(float percentage) {
    return new Point(origin->x + (length * percentage) * cosf(angleInRadians), origin->y + (length * percentage) * sinf(angleInRadians));
}

Point* Ray::pointAtYPos(float yPos) {
    float B = origin->y - (slope() * origin->x);
    return new Point((yPos - B) / slope(), yPos);
}

Ray::~Ray() {
    std::cout << "point released" << std::endl;
    origin.release();
    std::cout << "ray destroyed" << std::endl;
}

Третья строка, где появляется ошибка.

std::unique_ptr<Point> point(new Point(x,y));
std::unique_ptr<Ray> ray(new Ray(*point, M_PI/4, 100));
std::cout << "RAY origin: " << ray->origin->x << ", " << ray->origin->y << std::endl;

2 ответа

Решение

Я считаю, что это должно сработать - я буквально удалил все указатели из вашего кода и использовал вместо них экземпляры. На вашем уровне знаний C++, указатели почти всегда не нужны.

class Point {
    public:
        Point();
        Point(float x, float y);
        ~Point();

        float x;
        float y;
};

Point::Point() {
    x = 0;
    y = 0;
}

Point::Point(float xPos, float yPos) : x(xPos), y(yPos) {
    std::cout << "point created at: " << x << ", " << y << std::endl;
}

Point::~Point() {
    std::cout << "point destroyed" << std::endl;
}

class Ray {
    public:
        Ray(const Point& origin, float angleInRadians, float length);
        ~Ray();

        float slope();
        Point pointAtDistance(float percentage);
        Point pointAtYPos(float yPos);

        Point origin;

        float angleInRadians;
        float length;
};

Ray::Ray(const Point& o, float a, float l) : origin(o), angleInRadians(a), length(l) {
}

float Ray::slope() {
    return tanf(angleInRadians);
}

Point Ray::pointAtDistance(float percentage) {
    return Point(origin.x + (length * percentage) * cosf(angleInRadians), origin.y + (length * percentage) * sinf(angleInRadians));
}

Point Ray::pointAtYPos(float yPos) {
    float B = origin.y - (slope() * origin.x);
    return Point((yPos - B) / slope(), yPos);
}

Ray::~Ray() {
    std::cout << "ray destroyed" << std::endl;
}

Надеюсь, это поможет вам начать. Удачи с остальным заданием!

В вашем коде есть две проблемы: первая проблема, которая приводит к сбою, который вы испытываете, заключается в том, что ваши назначения в Ray конструктор нупс. В соответствии

origin = std::move(origin);

оба случая origin ссылаются на одну и ту же переменную (которая является локальной для функции). Следовательно, переменные в вашем классе остаются un/default-initialized. Для интеллектуального указателя инициализация по умолчанию означает, что он содержит указатель NULL, который вызывает ошибки при обращении к нему.

Тем не менее, изменение вашего конструктора для использования списков инициализатора, что позволяет избежать этой проблемы

Ray::Ray(Point& origin, float angleInRadians, float length) :
    origin(&origin), angleInRadians(angleInRadians), length(length)
{}

не удалит сбой из-за второй проблемы в вашем коде: вы создаете два разных unique_ptr<>s для того же объекта: первый unique_ptr<> называется pointвторой unique_ptr<> называется origin в классе Ray, Итак, ваша программа пытается уничтожить Point объект дважды, один раз, когда переменная point выходит из области видимости, второй, когда переменная ray выходит за рамки.

При использовании "умных" указателей стандартных библиотек C++ крайне важно никогда не преобразовывать умный указатель в пустой указатель / ссылку, а затем воссоздавать умный указатель из этого открытого указателя / ссылки. Вы в безопасности, если только назначаете умные указатели из умных указателей или передаете умные указатели по ссылке, но вы никогда не должны создавать два умных указателя, которые не знают друг друга для одного и того же объекта. Даже с shared_ptr<>это никогда не должно быть сделано. Если вы это сделаете, оба попытаются выполнить свою работу, и вы получите крах (надеюсь).


Sidenote (только мои 2 цента пристрастной мудрости):
Я полагаю, что указатели лучше всего понимаются не с использованием C++ и его "умных" указателей, а с помощью написания программ, использующих старый стиль, обнаженные указатели на C-стиле в действительности являются очень простой, очень мощной, хотя и довольно опасной вещью. И им нужен некоторый опыт, чтобы освоить. Сначала узнайте, что нужно сделать, чтобы безопасно использовать голые указатели; Как только вы это сделаете, у вас будет все необходимое понимание, чтобы использовать умные указатели во сне.

Другие вопросы по тегам