Aoik

C++ how returning an object is implemented

In Visual Studio 2015, create a Visual C++ -- Win32 Console Application empty project. In the project's Configuration Properties -- C/C++ -- Optimization page, set Optimization to Disabled (/Od).


Create main.cpp:

#include <iostream>
#include <string>


class Point
{
private:
    int m_x;
    int m_y;

public:
    Point(int x, int y) {
        std::cout << "Constructor" << std::endl;

        this->m_x = x;

        this->m_y = y;
    }

    Point(const Point& src) {
        std::cout << "Copy Constructor" << std::endl;

        this->m_x = src.m_x;

        this->m_y = src.m_y;
    }

    Point(const Point&& src) {
        std::cout << "Move Constructor" << std::endl;

        this->m_x = src.m_x;

        this->m_y = src.m_y;
    }

    Point& operator=(const Point& src) {
        std::cout << "Copy Assignment" << std::endl;

        this->m_x = src.m_x;

        this->m_y = src.m_y;

        return *this;
    }

    Point& operator=(const Point&& src) {
        std::cout << "Move Assignment" << std::endl;

        this->m_x = src.m_x;

        this->m_y = src.m_y;

        return *this;
    }
};


Point make_point(int x, int y)
{
    Point new_point {x, y};

    return new_point;
}


int main(int argc, char* argv[])
{
    Point point = make_point(0x11, 0x22);

    return 0;
}


The output of the program:

Constructor
Move Constructor


main's assembly code:

int main(int argc, char* argv[])
    // Push caller's EBP.
    push        ebp
    // Put caller's ESP to EBP.
    mov         ebp,esp
    // Reserve space for variable `point`.
    // [ebp-8]: Variable `point`.
    sub         esp,8
    // Push the second argument for `make_point` below.
    push        22h
    // Push the first argument for `make_point` below.
    push        11h
    // Put variable `point`'s address to EAX.
    lea         eax,[ebp-8]
    // Push variable `point`'s address as return value address for
    // `make_point` below.
    push        eax
    // Call `make_point`.
    call        make_point
    // Release the latest 3 pushes.
    add         esp,0Ch
    // Put return value 0 to EAX.
    xor         eax,eax
}


make_point's assembly code:

Point make_point(int x, int y)
{
    // Push caller's EBP.
    push        ebp
    // Put caller's ESP to EBP.
    // [ebp+10h]: Argument `y`.
    // [ebp+0Ch]: Argument `x`.
    // [ebp+8]: Return value.
    mov         ebp,esp
    // Reserve space for variable `new_point`.
    // [ebp-8]: Variable `new_point`.
    sub         esp,8
    // Put argument `y` to EAX.
    mov         eax,dword ptr [ebp+10h]
    // Push argument `y` as the second argument for constructor `Point::Point`
    // below.
    push        eax
    // Put argument `x` to ECX.
    mov         ecx,dword ptr [ebp+0Ch]
    // Push argument `x` as the first argument for constructor `Point::Point`
    // below.
    push        ecx
    // Put variable `new_point`'s address to ECX as `this` pointer for
    // constructor `Point::Point` below.
    lea         ecx,[ebp-8]
    // Call constructor `Point::Point`.
    call        Point::Point
    // Put variable `new_point`'s address to EDX.
    lea         edx,[ebp-8]
    // Push variable `new_point`'s address as the first argument for move
    // constructor `Point::Point` below.
    push        edx
    // Put return value's address to ECX as `this` pointer for move constructor
    // `Point::Point` below.
    mov         ecx,dword ptr [ebp+8]
    // Call move constructor `Point::Point`.
    call        Point::Point
    // Put return value's address to EAX.
    mov         eax,dword ptr [ebp+8]
    // Put caller's ESP to ESP.
    mov         esp,ebp
    // Pop caller's EBP to EBP.
    pop         ebp
    // Return.
    ret
}


As shown in the assembly code, make_point's return value's space is allocated in main's stack frame. The return value's address is pushed to stack as an implicit argument for make_point. make_point calls move constructor using the return value's address as this pointer.

Previous Post:
Next Post:

Comments:

Reply to: