我的问题(将在这之后提出,抱歉介绍太长,问题在粗体中)最初是受 Herb Sutters Exceptional C++ 我们在哪里找到这样的东西:
<截图>
...
int main()
{
GenericTableAlgorithm a( "Customer", MyWorker() );
a.Process();
}
with
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>
Now, I have the following problems with that code (and no, I in no way doubt Mr. Sutter's prowess as a C++ expert):
MyWorker used in the NVI of GenericTableAlgorithm accessed by GTAClient (polymorphic) interface; this rules out that the implementation owns a (value)member of type GTAClient, since that would cause slicing etc. value-semantics don't mix well with polymorphism.
MyWorker either since that class is unknown to GenericTableAlgorithm.
MyWorker()) are rarely a good idea, i assume the author's plan was to use the extended life-time of temporaries bound to (const) references, and store such a reference in the object pimpl_ points to and use it from there. (Note: there is also no clone-member function in GTAClient, which could have made this work; let's not assume there is a RTTI-typeinfo-based Factory lurking in the background.)
The standard in §12.2.5(the C++0x version but it's the same in C++, don't know about the chapter number) makes the following exception from lifetime extension:
"-A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits."
Therefore the object cannot be used in the call of the client code a.Process(); because the referenced temporary from MyWorker() is already dead!
Consider now an example of my own crafting that demonstrates the problem (tested on 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 call(): 0x7fff5fbff780:400 call(): 0x7fff5fbff770:1000 ~oogie():0x7fff5fbff780:400
您可以看到,在 const oogie& ref 的情况下,func() 的立即绑定(bind)到引用的临时返回值具有延长的所述引用的生命周期(直到 main 结束),所以没关系。
但是:1000-oogie 对象在 kangoo-s 构造完成后就已经被销毁了。代码有效,但我们在这里处理的是一个不死物体......
所以再次提出问题:
首先,我是否遗漏了什么代码是否正确/合法?。
其次,为什么 GCC 没有给我警告,即使指定了 -Wall?应该吗?可以吗?
谢谢你的时间,
马丁
最佳答案
我认为这是一个不太清楚的棘手部分。几天前有一个类似的问题。
默认情况下,当创建它们的完整表达式完成时,临时对象以相反的构造顺序被销毁。到目前为止,一切都很好并且可以理解,但随后出现异常 (12.2 [class.temporary]/4,5),事情变得困惑。
我将从工程/编译器的角度处理问题,而不是处理标准中的确切措辞和定义。临时对象在堆栈中创建,当函数完成时,堆栈帧被释放(堆栈指针移回函数调用开始前的原始位置)。
这意味着临时对象永远无法在创建它的函数中存活下来。更确切地说,它无法在定义它的范围内存活,即使它实际上可以在创建它的完整表达式 内存活。
标准中的所有异常(exception)都不受此限制,在所有情况下,临时文件的生命周期都会延长到保证不超过创建临时文件的函数调用的时间点。
关于c++ - 这个 C++ 临时绑定(bind)到引用成员应该是非法的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1477028/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我正在尝试在Rails上安装ruby,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我今天看到了一个ruby代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem
我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“