неожиданное поведение shared_pointer

Есть кусок кода:

A.cpp

class MySomeClass: public SomeClass
{
   public: 
   void specificMethod();
}

class A
{
    public:
    A::A();

    std::shared_ptr< B > m_bObject;
    std::shared_ptr< MySomeClass > m_argument;
}

A::A()
{
    m_argument= std::make_shared< MySomeClass >();
    m_bObject = std::make_shared< B >( m_argument);
}

B.cpp

B::B(const std::shared_ptr< SomeClass >& smartOne):m_smartOne(smartOne)
{}

B::someMethod()
{
    m_smartOne->specificMethod();
}

B.h

class B
{
public:
    B(const std::shared_ptr< SomeClass >& smarOne);
    void someMethod();

private:
    const std::shared_ptr< SomeClass >& m_smartOne;
};

Проблема в том, что когда я вызываю m_bObject->someMethod(), возникает дамп ядра, потому что m_smartOne не MySomeClass, а SomeClass.
Почему? Это проблема с областью действия, проблема с владением или что-то еще?
Я получил код класса B и не могу его изменить.


person rainbow    schedule 05.07.2017    source источник
comment
const std::shared_ptr< SomeClass >& m_smartOne; Что за бред?   -  person T.C.    schedule 05.07.2017
comment
@StoryTeller Не совсем. Я вижу минимальную выгоду от хранения shared_ptr по значению и много головной боли.   -  person T.C.    schedule 05.07.2017
comment
Я заметил эту конструкцию, но я новичок в использовании общих указателей и не знаю, почему это плохо.   -  person rainbow    schedule 05.07.2017
comment
@Т.С. - Я удалил свой комментарий, когда понял, что вы имеете в виду. Думал, что конструктор принимает его по ссылке, что может иметь смысл. Член - чистая чепуха, как ты и сказал.   -  person StoryTeller - Unslander Monica    schedule 05.07.2017


Ответы (1)


Когда std::make_shared<B>(m_argument) создаст объект B, он создаст временный объект shared_ptr<SomeClass> из m_argument типа shared_ptr<MySomeClass>. Ссылка на этот временный объект передается конструктору B, в котором хранится ссылка, которая сразу же стала зависшей, поскольку временный объект уничтожается после завершения вызова конструктора.

Результатом использования висячей ссылки, конечно же, является неопределенное поведение. Все может случиться.

Если вы не можете коснуться B, то лучшее, что вы можете сделать, это, вероятно, сделать так, чтобы A сохранял shared_ptr<SomeClass> элемент, чтобы не создавать временных. Но даже тогда A будет эффективно хранить ссылку в себе, а это означает, что конструкторы копирования/перемещения по умолчанию и операторы присваивания будут делать неправильные вещи. Это гигантская банка червей.

person T.C.    schedule 05.07.2017
comment
Но m_argument является членом, и я ожидаю, что он будет доступен во время жизни класса. Насколько я понимаю, во время make_shared‹B› создается ДРУГОЙ временный shared_ptr на основе m_argument. Я прав? - person rainbow; 05.07.2017
comment
Если вы не можете коснуться B, вам следует быстро убежать. - person n. 1.8e9-where's-my-share m.; 05.07.2017
comment
@rainbow m_argument имеет тип shared_ptr<MySomeClass>, конструктор B хочет shared_ptr<SomeClass> const&, поэтому вам нужно создать временный shared_ptr<SomeClass> из m_argument. - person Holt; 05.07.2017
comment
@rainbow Нет, static_pointer_cast также создаст временный файл. - person Holt; 05.07.2017
comment
@rainbow Если A владеет B, то у вас должно быть unique_ptr<B> вместо shared_ptr<B>, и вы должны просто сохранить SomeClass & или SomeClass * в B. - person Holt; 05.07.2017