shared_pointer 意外行为
shared_pointer unexpected behaviour
有一段代码:
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
class 的代码,无法更改。
当std::make_shared<B>(m_argument)
构造B
对象时,它将从m_argument
创建一个临时shared_ptr<SomeClass>
对象,类型为shared_ptr<MySomeClass>
。对该临时对象的引用被传递给 B
的构造函数,该构造函数存储一个引用,该引用在构造函数调用完成后临时对象被销毁时立即变为悬空。
使用悬空引用的结果当然是未定义的行为。什么事都有可能发生。
如果您无法触及 B
,那么最好的办法可能是让 A
存储一个 shared_ptr<SomeClass>
成员,这样就不会创建临时文件。但即便如此 A
也会有效地将引用存储到自身中,这意味着默认的 copy/move 构造函数和赋值运算符都会做错事情。那是一个巨大的蠕虫罐头。
有一段代码:
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
class 的代码,无法更改。
当std::make_shared<B>(m_argument)
构造B
对象时,它将从m_argument
创建一个临时shared_ptr<SomeClass>
对象,类型为shared_ptr<MySomeClass>
。对该临时对象的引用被传递给 B
的构造函数,该构造函数存储一个引用,该引用在构造函数调用完成后临时对象被销毁时立即变为悬空。
使用悬空引用的结果当然是未定义的行为。什么事都有可能发生。
如果您无法触及 B
,那么最好的办法可能是让 A
存储一个 shared_ptr<SomeClass>
成员,这样就不会创建临时文件。但即便如此 A
也会有效地将引用存储到自身中,这意味着默认的 copy/move 构造函数和赋值运算符都会做错事情。那是一个巨大的蠕虫罐头。