Detailed breakdown of the life cycle of C++ temporary objects

  • 2020-04-02 01:31:05
  • OfStack

There are three scenarios for the life cycle of a temporary object:

1) general situation:
The destruction of a temporary object should be the last step in the evaluation of a full expression. The full expression causes the creation of a temporary object.

Example code is as follows:

#include <iostream>
using namespace std;
class A
{
public:
    A(int i): m_i(i)
    {
        cout << "A(): " << m_i << endl;
    }
    ~A()
    {
        cout << "~A(): " << m_i << endl;
    }
    A operator+(const A& rhs)
    {
        cout << "A operator+(const A& rhs)" << endl;
        return A(m_i + rhs.m_i);
    }
    int m_i;
};
int main()
{
    A a1(1), a2(2);
    a1 + a2;
    cout << "------------------------------------" << endl; //At this point, the temporary variable created by a1 + a2 has been released
    return 0;
}

The running result is:

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201309/201309120939056.jpg ">

2) Any temporary object that contains the result of an expression execution should remain until the initialization of the object is complete.
The sample code is as follows:


#include <iostream>
using namespace std;
class A
{
public:
    A(int i = 0): m_i(i)
    {
        cout << "A(): " << m_i << endl;
    }
    ~A()
    {
        cout << "~A(): " << m_i << endl;
    }
    A operator+(const A& rhs)
    {
        cout << "A operator+(const A& rhs)" << endl;
        return A(m_i + rhs.m_i);
    }
    A& operator=(const A& rhs)
    {
        cout << "A& operator=(const A& rhs)" << endl;
        m_i += rhs.m_i;
        return *this;
    }
    int m_i;
};
int main()
{
    A a1(1), a2(2);
    A a3;
    a3 = a1 + a2; //The temporary variables generated by a1 + a2 are released after the assignment operation in a3 is completed
    return 0;
}

The running result is:


< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201309/201309120939057.jpg ">

3) If a temporary object is bound to a reference, the object remains until the life of the initialized reference is over, or until the life scope of the temporary object is over, depending on which case is reached first.

The sample code is as follows:

#include <iostream>
using namespace std;
class A
{
friend ostream& operator<<(ostream& os, const A&);
public:
    A()
    {
    }
    A(const A&)
    {
        cout << "A(const A&)" << endl;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }
};
ostream& operator<<(ostream& os, const A&)
{
    os << "ostream& operator<<(ostream& os, const A&)" << endl;
    return os;
}
const A& f(const A& a)
{
    return a;
}
int main(int argc, char* argv[])
{
    {
        const A& a = A();
        cout << "-------------------" << endl;
    }//Until the life of the initialized reference is over
    cout  << f(A()) << endl; //Until the end of the temporary object's scope:
                             //The const reference for the temporary object is on the parameter of f (not the return value).
                             //The reference ends when f() returns, but the temporary object is not necessarily destroyed.
    cout << "-------------------" << endl;

    return 0;
}

Operation results:

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201309/201309120939058.jpg ">

Related articles: