2011-09-05 90 views
8

我已经浏览过互联网,并且这个线程正在寻找一个完整的 回答我所面临的这种情况。我已经读过,扔智能指针 不是很聪明。我只是想明白为什么 是这样发生的。我将解释这种情况。让我们想象一下这个简单的 层次:智能指针和异常处理

class Foo 
{ 
public: virtual ~Foo() {} 
}; 

typedef tr1::shared_ptr<Foo> SPFoo; 

class FooInherited: public Foo { }; 

typedef tr1::shared_ptr<FooInherited> SPFooInherited; 

而且我们检查这个测试代码:

int main(int argc, char** argv) 
{ 
    try 
    { 
    throw FooInherited(); 
    } 
    catch(const Foo& f) 
    { 
    cout << "Foo& caught!" << endl; 
    } 
    try 
    { 
    throw SPFooInherited(new FooInherited()); 
    } 
    catch(const SPFoo& f) 
    { 
    cout << "SPFoo& caught!" << endl; 
    } 
    return 0; 
} 

一切编译,但在运行时 执行第二的try-catch不会。有人可以解释我为什么吗?特别是如果像 这样的代码行在运行时工作得很好。

void function(const SPFoo& f) 
{ 
} 

... 

SPFooInherited fi(new FooInherited()); 
function(fi); 

我明白,这个问题是SPFooInherited不会SPFoo(即使FooInherited从富继承)继承,但它深深地想知道什么是编译器/ RTE从函数调用示例做不同捕捉异常时不能解决问题。是否因为catch参数与函数调用参数不一样?为什么Foo &工作和SPFoo不?

非常感谢你提前。

Regards, Iker。

回答

13

正如你在你的问题中所说的,SPFooInherited不是SPFoo的子类。这意味着catch(SPFoo const&)将不会捕获SPFooInherited的实例。另一方面,FooInherited继承自Foo,因此catch(Foo const&)将捕获FooInherited的实例。

要理解这一点,您不需要对编译器或运行时环境有任何特别的理解。它只是语言的一部分。

调用函数的原因是tr1::shared_ptr有一个模板化的非显式构造函数,允许在函数调用位置进行隐式转换。

即:tr1::shared_ptr具有下面的构造:

//Note the lack of explicit 
template<class Y> shared_ptr(shared_ptr<Y> const & r); 

这允许shared_ptr从不同的共享指针类型来构造。此构造函数的实现依赖于从FooInherited*Foo*的隐式转换,以将SPFooInherited中的指针实际存储到SPFoo中。如果此隐式转换不存在,则代码将无法编译,因此不会出现shared_ptr到不相关类型之间的不安全转换。

函数调用和卡之间的根本区别是,隐式转换会发生在函数参数初始化,但一个catch只能匹配单个类型(FooInherited是-A Foo,所以它会匹配)。

3

因为SPFoo不是SPFooInherited的子类。catch块只会捕获其捕获列表中的东西,或者捕获列表中的公共子类。 FooInherited确实从Foo开始,因此抓住Foo也可以让您发现FooInheritedSPFooSPFooInherited是完全不同和无关的类。