本文是小编为大家收集整理的关于暂时延长寿命的参考的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。
问题描述
我对某些C ++标准合规性或缺乏它有疑问.
在我的项目中,我使用的是一些使用const参考技巧的简单护罩类.我使用的是Visual Studio 2005,有两种配置 - 一种用于普通释放构建,第二个用于单位测试.
在这两种情况下,最终都有一些临时悬挂在const参考上,但是同时发生的是问题.对于释放配置,const引用直接指向创建护罩实例的辅助函数模板中创建的温度(没有调用复制构造函数,甚至没有实例化).
但是,对于单位测试conf,首先复制函数模板温度,然后调用其驱动器,只有在const引用范围内才能完成的操作.
.我已经通过在基类复制构造器中禁用原始后卫解决了该问题(因此,destructor中的操作并未触发用于调用复制构造器的配置),但是令我困扰的是:
副本行为是符合标准的吗?该标准是否告诉const引用应直接指向温度,还是标准中未指定的实现定义的行为?
我的代码大致基于DDJ和Herb Sutter的Gotw 88文章的范围守卫文章,但是这两个来源似乎都没有考虑到较早的Destructor呼叫.
任何知识渊博的人的信息都将不胜感激.
编辑:
好的代码就是这样:
class GuardBase { public: GuardBase() : m_enabled(true) {} //this is done because in normal build no copy constructor is called ( directly using the function temporary) //but for UT conf somehow the original temp is copied and destroyed GuardBase(const GuardBase& other) { other.disable(); } void disable() const { m_enabled = false; } protected: //member is mutable because we will access the object through the const reference mutable bool m_enabled; }; template< typename Arg, typename ObjType, typename MemberMethod > class Guard1Arg : public GuardBase { public: Guard1Arg(ObjType& obj, MemberMethod remover, Arg arg) : m_arg(arg), m_remover(remover), m_object(obj) {} ~Guard1Arg() { if ( m_enabled ) { (m_object.*m_remover)(m_arg); } } private: Arg m_arg; MemberMethod m_remover; ObjType& m_object; //this class should not be assigned Guard1Arg& operator=(const Guard1Arg& other); }; //utility template function used to create Guards using member functions with 1 argument template<typename MemberFunction, typename Obj, typename Arg> Guard1Arg<Arg, Obj, MemberFunction> MakeGuard1Arg(Obj& obj, MemberFunction memberFunction, Arg& arg) { return Guard1Arg<Arg, Obj, MemberFunction>(obj, memberFunction, arg); } #define GUARD_CREATE(arg, remover) const GuardBase& guard = MakeGuard1Arg(*this, remover, arg); #define GUARD_DISABLE guard.disable(); #define GUARD_FRIEND template< typename Arg, typename ObjType, typename MemberMethod > friend class Guard1Arg;
推荐答案
这两种行为都是标准的. 如果您有这样的代码:
T foo() { return T(); } int main() { const T& x = foo(); }
然后,从概念上讲,在foo中,创建一个临时对象.该临时性被复制到foo的返回值.在main中,此副本(也是临时对象)与x绑定.
foo的返回价值的副本延长了其寿命,但不是临时的.
,但是,C ++标准明确允许冗余临时对象.因此,foo可以直接在该插槽中创建临时性.
这两个选项都是可能的,并且在使用哪个选项时,编译器甚至不需要记录.
C ++标准的相关部分为6.6.3([STMT.Return])和12.2([[class.temporary]).
问题描述
I have a question about some C++ standard compliance or lack of it.
In my project I'm using some simple Guard class that uses the const reference trick. I'm using Visual Studio 2005 and there are two configurations - one for normal release build and the second one for unit tests.
In both cases there is some temporary hanging on the const reference in the end, but what happens in the meantime is the problem. For release configuration, the const reference points directly to the temp created in the return of the helper function template that creates the Guard instance ( no copy constructor is called, not even instantiated for that matter ).
But for unit test conf the function template temp is first copied and then its destructor is called, doing what should be done only after the const reference goes out of scope.
I have solved the problem by disabling the original guard in base class copy constructor ( so the action in destructor is not triggered for config for which copy constructor is called ), but what bothers me is:
Is the copy-the-temporary behaviour standard-compliant? Does the standard tells that the const reference should point directly to the temp, or is this implementation-defined behaviour not specified in the standard?
I have based my code roughly on Scope Guard article in DDJ and Herb Sutter's gotw 88 article, but both those sources don't seem to take the earlier destructor call into account.
Any info from someone more knowledgeable will be appreciated.
EDIT:
Ok the code is something like this:
class GuardBase { public: GuardBase() : m_enabled(true) {} //this is done because in normal build no copy constructor is called ( directly using the function temporary) //but for UT conf somehow the original temp is copied and destroyed GuardBase(const GuardBase& other) { other.disable(); } void disable() const { m_enabled = false; } protected: //member is mutable because we will access the object through the const reference mutable bool m_enabled; }; template< typename Arg, typename ObjType, typename MemberMethod > class Guard1Arg : public GuardBase { public: Guard1Arg(ObjType& obj, MemberMethod remover, Arg arg) : m_arg(arg), m_remover(remover), m_object(obj) {} ~Guard1Arg() { if ( m_enabled ) { (m_object.*m_remover)(m_arg); } } private: Arg m_arg; MemberMethod m_remover; ObjType& m_object; //this class should not be assigned Guard1Arg& operator=(const Guard1Arg& other); }; //utility template function used to create Guards using member functions with 1 argument template<typename MemberFunction, typename Obj, typename Arg> Guard1Arg<Arg, Obj, MemberFunction> MakeGuard1Arg(Obj& obj, MemberFunction memberFunction, Arg& arg) { return Guard1Arg<Arg, Obj, MemberFunction>(obj, memberFunction, arg); } #define GUARD_CREATE(arg, remover) const GuardBase& guard = MakeGuard1Arg(*this, remover, arg); #define GUARD_DISABLE guard.disable(); #define GUARD_FRIEND template< typename Arg, typename ObjType, typename MemberMethod > friend class Guard1Arg;
推荐答案
Both behaviours are standards conforming. If you have code like this:
T foo() { return T(); } int main() { const T& x = foo(); }
Then, conceptually, in foo, a temporary object is created. This temporary is copied to the return-value of foo. In main, this copy (which is also a temporary object) is bound to x.
The copy that is the return-value from foo gets its lifetime extended, but not the temporary that was the source for the copy.
But, the C++ standard explicitly allows redundant temporary objects to be elided. So instead of creating a temporary and copying that over into the slot for return values, foo can directly create the temporary in that slot.
Both options are possible, and the compiler does not even have to document when it uses which option.
The relevant sections of the C++ standard are 6.6.3 ([stmt.return]) and 12.2 ([class.temporary]).