我有一个Base类和一个Derived类。 API仅公开Derived,并且实现隐藏在Base中(gcc属性visibility
设置为hidden
),因为一些内部API模块必须调用Base方法。
这样我们得到了:
// Base.h
class Derived;
class Base
{
typedef std::tr1::shared_ptr<Derived> DerivedPtr;
public:
void doSomething(DerivedPtr aDerived);
protected:
Base();
};
// Derived.h
class Derived : public std::tr1::enable_shared_from_this<Derived>, public Base
{
public:
Derived():std::tr1::enable_shared_from_this<Derived>(), Base(){}
void doSomething(DerivedPtr aDerived)
{
Base::doSomething(aDerived);
}
};
现在doSomething
的作用如下:
void Base::doSomething(DerivedPtr aDerived)
{
DerivedPtr lDerived = reinterpret_cast<Derived*>(this)->shared_from_this();
}
问题如下:
std::tr1::bad_weak_ptr
异常; 我正在使用gcc-4.4.7,而我从backtrace中可以看到它被称为:
std::tr1::enable_shared_from_this<Derived>::shared_from_this
std::tr1::shared_ptr<Derived>::shared_ptr<Derived> (this=0x7fffffffd370, __r=std::tr1::weak_ptr (empty) 0x2)
std::tr1::__shared_ptr<Derived, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<Derived>
std::tr1::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count
在__shared_count
中它会抛出,因为:
292 template<_Lock_policy _Lp>
293 inline
294 __shared_count<_Lp>::
295 __shared_count(const __weak_count<_Lp>& __r)
296 : _M_pi(__r._M_pi)
297 {
298 if (_M_pi != 0)
299 _M_pi->_M_add_ref_lock();
300 else
301 __throw_bad_weak_ptr();
302 }
我的__r._M_pi等于0。
我知道在Derived
中使用Base
可能是一个糟糕的主意,但这不是主题的问题,让我们按原样来看待它。 (没有人可以直接实例化Base
。
客户(使用API的人)使用shared_ptr的重要性,这就是Derived继承enable_shared_from_this
的原因。
我正在尝试做的是了解发生了什么以及为什么抛出bad_weak_ptr
异常以及我该怎么做才能避免它(可能是架构中的一些小变化)。
我根据https://stackoverflow.com/a/9377075/1498245
更改了Base::doSomething
现在看起来像:
void Base::doSomething(DerivedPtr aDerived)
{
DerivedPtr lDerived = std::tr1::static_pointer_cast<Derived>( static_cast<Derived*>(this)->shared_from_this() );
}
它可能开始起作用了。可能,因为不再有例外,但我不太确定下面发生了什么。在reinterpret_cast
期间看起来有一些数据丢失。在我的实际案例中,Base
类更大,有很多成员,等等。也许就是这种情况。谁能对这个案子有所启发?发生了什么“引擎盖下”?
答案 0 :(得分:1)
问题如下:
•当我使用如上所示的简单示例时 - 它工作正常;
•当我在我的大项目中使用它时 - 它会抛出std :: tr1 :: bad_weak_ptr异常;
这听起来像未定义的行为。
有两种可能性会浮现在脑海中(因为您没有在测试代码和项目之间发布差异,我在这里猜测):
我的第一个猜测就是这段代码:
DerivedPtr lDerived = reinterpret_cast<Derived*>(this)->shared_from_this();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
您确定仅从派生实例调用Base::doSomething
吗?从层次结构的基础派生出来是一个不安全的演员。
我的第二个猜测是你正在为不是指针的东西调用shared_from_this。我正在谈论的场景的一个例子:
struct Foo : public std::enable_shared_from_this<Foo> {
std::shared_ptr<Foo> share() { return shared_from_this(); }
};
std::shared_ptr<Foo> pf(new Foo);
auto pf2 = pf->share(); // OK, pf2 will share ownership with pf
Foo localInstance;
auto pf2 = localInstance.share(); // NOT OK, pf2 will attempt to delete a local
// value at scope end