Ошибка сегментации при использовании Определяемого оператора преобразования - PullRequest
0 голосов
/ 01 октября 2019

Я реализовал следующий фрагмент кода

#include <iostream>
#include <memory>

class A
{
    public:
        int a;

        virtual ~A()
        {
        }
};

class B : public A
{
    public:
        int b;

        virtual ~B()
        {
        }
};

class E : public B
{
    public:
        ~E()
        {
        }
};

class D
{
public:
    operator std::shared_ptr<A>()
    {
        std::shared_ptr<A> pa = std::make_shared<A>();
        pa->a = this->y;
        return pa;
    }

    operator std::shared_ptr<B>()
    {
        std::shared_ptr<A> pb = std::make_shared<B>();

        pb = *this;
        (std::static_pointer_cast<B>(pb))->b = this->x;
        return std::static_pointer_cast<B>(pb);
    }

    virtual ~D()
    {
    }

    int x;
    int y;
};

int main()
{
    D d;
    d.x = 6;
    d.y = 7;
    std::shared_ptr<E> pE = std::make_shared<E>();
    std::shared_ptr<A> pa = pE;

    std::shared_ptr<B> pB = std::dynamic_pointer_cast<B>(pa);
    pB = d;
    std::cout << "a " << pB->a << "b " << pB->b << std::endl;
    return 0;
}

Я пытаюсь преобразовать экземпляр класса D, d в экземпляр общего указателя B, которыйявляется производным от класса A.

B наследует класс A, а E наследует класс B.

Когда программа завершается, программа падаетв деструкторе класса A.

я использовал GDB и вижу, что this равен NULL.

У кого-нибудь есть идеи, почему это происходит?

1 Ответ

3 голосов
/ 01 октября 2019

Внутри D::operator std::shared_ptr<B>() использование std::static_pointer_cast<B>(pb) является неопределенным поведением , потому что pb не указывает на экземпляр B в этой точке, поэтому запрещается разыгрыватьA указатель на B указатель и доступ к B членам. pb указывает на экземпляр A, созданный std::make_shared<A>() в D::operator std::shared_ptr<A>(). В операторе pb = *this; вы отбрасываете созданный вами объект B и становитесь владельцем объекта A, возвращаемого *this.

Таким образом, внутри main(), pB заканчиваетсяуказывает на недопустимый объект B и пытается уничтожить этот объект при выходе из main(), поэтому вы в конечном итоге разбили деструктор A.

Если бы вы использовали dynamic_pointer_cast вместо static_pointer_cast внутри D::operator std::shared_ptr<B>() вы бы получили нулевой указатель и, скорее всего, потерпели бы крах внутри D::operator std::shared_ptr<B>() при доступе к B::b вместо сбоя main().

Вам нужно исправить operator std::shared_ptr<B>() для работы с действительным экземпляром B, а не с экземпляром A. Например:

operator std::shared_ptr<B>()
{
    std::shared_ptr<B> pb = std::make_shared<B>();
    std::shared_ptr<A> pa = *this;

    *static_pointer_cast<A>(pb) = *pa; // <-- copy pa->a to pb->a ...
    // or: simply do this instead:
    // pb->a = pa->a;

    pb->b = this->x;
    return pb;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...