我的问题(这将在此之后出现,对于冗长的介绍感到抱歉,问题在下面以粗体显示)最初是受到 Herb Sutters Exceptional C++中的第 23 项的启发,我们在其中找到了类似的内容:
<snip>
...
int main()
{
GenericTableAlgorithm a( "Customer", MyWorker() );
a.Process();
}
和
class GenericTableAlgorithm
{
public:
GenericTableAlgorithm( const string& table,
GTAClient& worker );
bool Process();
private:
struct GenericTableAlgorithmImpl* pimpl_; //implementation
};
class GTAClient
{
///...
virtual bool ProcessRow( const PrimaryKey& ) =0;
//...
};
class MyWorker : public GTAClient
{
// ... override Filter() and ProcessRow() to
// implement a specific operation ...
};
</snip>
现在,我对该代码有以下问题(不,我毫不怀疑 Sutter 先生作为 C++ 专家的能力):
- 像这样的例子是行不通的,因为 GTAClient& worker 是一个非常量引用,不能临时引用,但是好吧,它可能是按标准编写的或者是错字,无论如何,这不是我的意思。
- 让我想知道的是他将如何处理工人参考,即使问题 1. 被忽略。
显然本意是用在通过(多态)接口访问MyWorker
的NVI中;这排除了实现拥有 type 的(值)成员,因为这会导致切片等。值语义不能与多态性很好地混合。 它也不能具有类型的数据成员,因为该类对于. 所以我得出结论,它一定是通过指针或引用来使用的,保留了原始对象和多态性。GenericTableAlgorithm
GTAClient
GTAClient
MyWorker
GenericTableAlgorithm
- 由于指向临时对象
MyWorker()
(pimpl_
. (注意:GTAClient 中也没有 clone-member 函数,它可以完成这项工作;我们不要假设有一个基于 RTTI-typeinfo 的工厂潜伏在后台。)
在这里(终于!)我的问题是: (如何)可以合法地将临时 to 传递给具有延长生命周期的类的引用成员?
§12.2.5 中的标准(C++0x 版本,但在 C++ 中相同,不知道章号)从生命周期扩展中产生以下异常:
“-A 临时绑定到构造函数中的引用成员ctor-initializer (12.6.2) 一直存在,直到构造函数退出。”
因此该对象不能用于调用客户端代码a.Process(); 因为引用的临时 fromMyWorker()
已经死了!
现在考虑一个我自己制作的示例来演示该问题(在 GCC4.2 上测试):
#include <iostream>
using std::cout;
using std::endl;
struct oogie {
~oogie()
{
cout << "~oogie():" << this << ":" << m_i << endl;
}
oogie(int i_)
: m_i(i_)
{
cout << "oogie():" << this << ":" << m_i << endl;
}
void call() const
{
cout << "call(): " << this << ":" << m_i << endl;
}
int m_i;
};
oogie func(int i_=100)
{
return oogie(i_);
}
struct kangoo
{
kangoo(const oogie& o_)
: m_o(o_)
{
}
const oogie& m_o;
};
int main(int c_, char ** v_)
{
//works as intended
const oogie& ref = func(400);
//kablewy machine
kangoo s(func(1000));
cout << ref.m_i << endl;
//kangoo's referenced oogie is already gone
cout << s.m_o.m_i << endl;
//OK, ref still alive
ref.call();
//call on invalid object
s.m_o.call();
return 0;
}
产生输出
oogie():0x7fff5fbff780:400 oogie():0x7fff5fbff770:1000 ~oogie():0x7fff5fbff770:1000 400 1000 调用():0x7fff5fbff780:400 调用():0x7fff5fbff770:1000 ~oogie():0x7fff5fbff780:400
您可以看到,在const oogie& ref的情况下,func() 的立即绑定到引用的临时返回值具有所述引用的延长生命周期(直到 main 结束),所以没关系。
但是: 1000-oogie 对象在 kangoo-s 被构建后就已经被销毁了。代码有效,但我们在这里处理的是一个不死物体......
所以再次提出这个问题:
首先,我在这里遗漏了什么并且代码是正确/合法的吗?.
其次,为什么 GCC 没有给我任何警告,即使指定了 -Wall ?应该是?可以吗?
谢谢你的时间,
马丁