临时对象(temporary object)

#include<iostream>
using namespace std;

class T
{
public:
    int data;
    T()
    {
        data = 10;
        cout << "T()" << endl;
    }
    T(const T &tmp)
    {
        data = tmp.data;
        cout << "T(const T &)" << endl;
    }
};

T operator + (const T &a, const T &b)
{
    T tmp;
    tmp.data = a.data + b.data;

    return tmp;
}

int main()
{
    T a,b;
    T c = a+b;return 0;
}

Whether a temporary results depends int part on the aggressiveness of the compiler and in part on the program context in which the expression occurs.

    T a,b;
    T c = a+b;

对于上面的代码,有三种可能的情况:

1、产生临时对象

T a;
a.T::T();    // 输出T()
T b;
b.T::T();    // 输出T()

T d;         // 注意不调用构造函数
a+b;         // 在operator + 中,tmp.T::T()输出T(),然后d.T::T(tmp)输出T(const T &)

T c;
c.T::T(d);   //输出T(const T &)

2、不产生临时对象,不使用NRV具名返回值优化

T a;
a.T::T();    // 输出T()
T b;
b.T::T();    // 输出T()

T c;         // 注意不调用构造函数
a+b;         // 在operator + 中,tmp.T::T()输出T(),然后d.T::T(c)输出T(const T &)

3、使用NRV具名返回值优化

T a;
a.T::T();    // 输出T()
T b;
b.T::T();    // 输出T()

T c;         // 注意不调用构造函数
a+b;         // 在operator + 中,c.T::T()输出T()

其中,1和2的情况下,operator+被转换成下面的形式:

void operator + (const T &result, const T &a, const T &b)
{
    T tmp;
    tmp.data = a.data + b.data;
    result.T::T(tmp);

    return ;
}

在3中开启具名返回值优化的情况下:

void operator + (const T &result, const T &a, const T &b)
{
    result.T::T();
    result.data = a.data + b.data;

    return ;
}

 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

与T c = a+b功能相同的赋值语句c = a+b却需要临时对象的辅助。

T temp;
operator +(temp, a,b);

c.operator =(temp);
temp.T::~T();

      如果我们不使用临时对象temp,而是像T c=a+b中的那样直接把c传递给operator+会发生什么呢?我们知道,在operator+中,无论是否开启NRV,result都不会进行destructor析构操作,result只会调用自己的某一个构造函数。但是,operator+希望传递给他的result是一块raw memory。因为,如果result之前已经被初始化过了,而恰巧类T中有一个int * pInt的指针数据成员,那么在operator+中pInt指向的内存将不会得到释放,即发生了内存泄露。所以为了解决这一问题,编译器可能将c=a+b转换为c.T::~T()和c.T::T(a+b)。然而,destructor,copy constructor和copy assignment operator它们可能是用户自己定义的函数,所以destructor和copy constructor的结合并不一定会得到与copy assignment operator相同的结果。所以,赋值语句c=a+b需要临时对象的帮助。

Here is an initialization that is guaranteed to fail under the new lifetime of temporaries rule(temporary objects are destroyed as the last step in evaluating the full expression that contains the point where they were created)

const char *nameVersion = name + version;

the presumption in this example of a String class is that the class defines a conversion operator of the form: String::operator const char *(){return _str;}. name and version are String objects. The code generated for this looks something like:

String temp;
operator(temp,name,version);
nameVersion = temp.String::operator const char *();
temp.String::~String();

namVersion now points into undefined heap memory.

One exception to the lifetime of temporaries rule concerns when a temporary is bound to a reference.

const Stirng &space = "";  The code generated for this looks something like:

Stirng temp;
temp.String::String(" ");
const String &space = temp;

if the temporary were destroyed now, the reference would be slightly less than useless. So the rule is that a temporary bound to a reference persists for the lifetime of the reference initialized or until the end of the scope in which the temporary is created, whichever is first.

posted on 2014-05-15 11:18  江在路上2  阅读(186)  评论(0)    收藏  举报