How the compiler of the C + + object model handles functions returns an object

Source: Internet
Author: User

1, inconsistent with the output of experiencewe know that when one of the following three situations occurs, the copy constructor for the class that corresponds to the object is called:1) When an object is initialized for display
2) When an object is passed as a parameter to a function3) When the function returns an object of a class
So, when we design a function (normal or member function), experience tells us that, for efficiency reasons, you should return as many pointers or references to an object as possible, rather than returning an object directly. Because returning an object directly may cause the object's copy construction process, this means that a certain amount of memory replication and object creation actions occur, which reduces the efficiency of the program. The idea of this design is correct, but in fact, when the function returns an object, does the above copy construction process necessarily occur?
For example, for the following code:
Class x{public    :        X ()        {            mdata = +;            cout << "x::x ()" << Endl;        }        X (const x& RHS)        {            mdata = rhs.mdata;            cout << "x::x (const X&RHS)" << Endl;        }        void SetData (int n)        {            mdata = n;        }        void print ()        {            cout << "x::mdata = =" << mdata << Endl;        }    Private:        int mdata;}; x func () {    x xx;    Xx.setdata (101);    return xx;} int main () {    X xx = func ();    return 0;}

looking at the code snippet above, what do you think the program should output? If it is analyzed according to the book, in the Func function, a local object XX of Class X is defined, so the constructor of Class X is called; the return value returned by the Func function is an object, so the function returns a copy of the object XX, so the copy constructor for class X is called In the main function, a local object XX of Class X is also defined, and the object is constructed from the object returned by the function Func as the initial value, so the copy of Class X is called because it is constructed. In other words, according to this analysis, the input result should be:X::x ()
x::x (const X&RHS)
x::x (const X&RHS)

originally I also thought the output should be the above three lines, but the actual operation results as shown, it is completely unexpected to me:

from the running result, only one line of "x::x ()" is output, that is, it only constructs a class X object, and there is no copy construction process. Our analysis basis is correct, the program code is very simple, the analysis process is also correct, but the behavior of the program and our analysis does not match it? In fact, everything is a compiler for the sake of optimization, secretly modified the code of our program. Here's a way to get the compiler to handle the return object, and then describe what the compiler's optimizations are doing to our code.
2. A method for the compiler to process the returned objectwhen the function call is complete, its local object is destroyed, and if the function returns a local object, how does the compiler copy the local object? Here's how:1) First add an extra parameter to the function, and the type is a reference to the class object. This parameter will be used to store the return value of the copy construct.2) Place a copy-construct call operation before the return instruction so that the contents of the object to be returned are treated as the initial value of the new parameter described above.
the two operations of the method rewrite the function so that it does not return any values. Depending on this method, the operation of the Func function may be converted to the following pseudo-code:
C + + pseudo-code, impersonation constructor and copy constructor call void func (x &__result) {    x xx;    Xx. X::x (); Call the default constructor for Class X       xx.setdata (101);       __result. X::x (XX); Call the copy constructor of Class X       return;}

now the compiler must convert each func () call operation to conform to its new definition, i.e.X xx = func ();
is converted into the following statement:x xx;//Do not call the constructor of Class Xfunc (xx);
Therefore, the main function is converted to the following pseudo-code
C + + pseudo-code, impersonation constructor and copy constructor call int main () {    x xx;//constructor for class X is not called    func (xx);    return 0;}

depending on the compiler's operation, the following output can be obtained:x::x ()
x::x (const X&RHS)The first behavior is the construction of the local object xx in the Func function, and the second behavior occurs in order to achieve the purpose of the copy construction operation. Although this result is different from the analysis in section 1th, the use of this method from compilation can reduce the call of a copy constructor, which improves the efficiency, after all, it is no good to copy the same object two times. And the compilation will be further optimized for this program, which will be described in detail in section 3rd.
Another use of the function func is to use the return value of the function func directly, without assigning it to a variable. Modify the main function to read as follows:
int main () {    func (). print ();    return 0;}

When this occurs, the compiler may convert the following to make the code run correctly:
C + + pseudo code, simulation compiler related processing operation int main () {    {        X __temp;        Func (__temp);        __temp.print ();    }}

in the case of the deep exploration of the C + + object model, the converted code is not placed in a curly brace, but I personally think it is more reasonable. Because the Func function returns a temporary object, as defined by C + +, when the statementfunc (). print ();
after the run is finished, the temporary variable should be destroyed. Put the converted statement in a pair of curly braces, and when you are finished running the converted statement, the __TEMP temporary variable is destroyed by the scope. But if the compiler does this, I don't know.
Similarly, if a function pointer variable is defined in the program and points to the function, the compiler also needs to overwrite the definition of the function pointer.
3, NRV optimizationin section 2nd, we have analyzed how the compiler handles functions that return an object, but the result is not the same as the output of our program, because the compiler has further optimized the program by replacing the name of the return value with the argument (result parameter) of the added class object reference (named return value).
with this policy, the Func function is converted to the following pseudo-code:
C + + pseudo code, simulation constructors and optimizations for copy constructors void func (X &__result) {    __result. X::x (); Call the default constructor for Class X       __result.setdata (101);       return;}

the pseudo-code after the main function is converted does not change, as follows:
int main () {    x xx;//does not call the constructor of class X    func (xx);    return 0;}

with this optimization, you can see that the constructor is called only once during the invocation of the main function, and the copy constructor is not called. Such a compile-optimized operation is known as named Return Value (NRV) optimization. NRV optimization is now considered an obligatory optimization operation for the standard C + + compiler. So the unexpected output from section 1th is the result of NRV optimization.
while NRV optimization provides significant efficiency improvements, optimizations are done silently by the compiler, and whether it is really done is not very clear, and once the function becomes more complex, optimization is difficult to implement.

How the compiler of the C + + object model handles functions returns an object

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.