在C ++中保证临时的生命期?
C ++是否为函数调用中创build的临时variables的生命周期提供了保证,但不作为参数使用? 下面是一个示例类:
class StringBuffer { public: StringBuffer(std::string & str) : m_str(str) { m_buffer.push_back(0); } ~StringBuffer() { m_str = &m_buffer[0]; } char * Size(int maxlength) { m_buffer.resize(maxlength + 1, 0); return &m_buffer[0]; } private: std::string & m_str; std::vector<char> m_buffer; };
以下是你将如何使用它:
// this is from a crusty old API that can't be changed void GetString(char * str, int maxlength); std::string mystring; GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
什么时候临时StringBuffer对象的析构函数被调用? 是吗:
- 在调用GetString之前?
- GetString返回后?
- 编译器依赖?
我知道C ++保证只要有一个引用它的地方临时variables将是有效的 – 这是否适用于父对象,当有一个成员variables的引用?
谢谢。
这种临时性的析构函数在全expression式的末尾被调用。 这是最外层的expression,不是任何其他expression的一部分。 在你的情况下,函数返回并评估值。 所以,它会工作的很好。
事实上,expression式模板的工作原理是:它们可以在expression式中保持对那种临时对象的引用
e = a + b * c / d
因为每个临时表将持续到expression式
x = y
完全评估。 标准中的12.2 Temporary objects
十分简洁。
litb的回答是准确的。 临时对象(也称为右值)的生命周期与expression式相关联,临时对象的析构函数在完整expression式的末尾被调用,当调用StringBuffer上的析构函数时,m_buffer上的析构函数也将被调用,但不是m_str上的析构函数,因为它是一个引用。
请注意,C ++ 0x只改变了一点,因为它增加了右值引用和移动语义。 基本上通过使用右值引用参数(用&&注释),我可以将右值“移动”到函数中(而不是复制它),并且右值的生命周期可以绑定到它所移入的对象,而不是expression式。 MSVC团队有一篇很好的博客文章,详细介绍了这一点 ,我鼓励大家阅读它。
移动右值的教学示例是临时string,我将在构造函数中显示赋值。 如果我有一个包含string成员variables的MyType类,它可以在构造函数中用右值初始化,如下所示:
class MyType{ const std::string m_name; public: MyType(const std::string&& name):m_name(name){}; }
这很好,因为当我用临时对象声明这个类的一个实例时:
void foo(){ MyType instance("hello"); }
会发生什么是我们避免复制和销毁临时对象,“hello”直接放置在拥有的类实例的成员variables中。 如果对象比“string”重,则额外的复制和析构函数调用可能是重要的。
调用GetString之后返回。
我写了几乎完全一样的课:
template <class C> class _StringBuffer { typename std::basic_string<C> &m_str; typename std::vector<C> m_buffer; public: _StringBuffer(std::basic_string<C> &str, size_t nSize) : m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; } ~_StringBuffer() { commit(); } C *get() { return &(m_buffer[0]); } operator C *() { return get(); } void commit() { if (m_buffer.size() != 0) { size_t l = std::char_traits<C>::length(get()); m_str.assign(get(), l); m_buffer.resize(0); } } void abort() { m_buffer.resize(0); } }; template <class C> inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize) { return _StringBuffer<C>(str, nSize); }
在标准之前,每个编译器都做了不同的处理。 我相信旧的C ++注释参考手册指出临时应该在范围的末尾清理,所以一些编译器也这样做了。 直到2003年,我发现在Sun的Forte C ++编译器中,行为依然存在,所以StringBuffer不起作用。 但是如果现在的编译器仍然有问题,我会感到惊讶的。
StringBuffer在GetString的范围内。 它应该在GetString范围的末尾(即返回时)被销毁。 另外,我不相信只要有参考,C ++就会保证一个variables的存在。
以下应该编译:
Object* obj = new Object; Object& ref = &(*obj); delete obj;