Std :: move and RVO optimization

I recently read how it std::movecan speed up code by simply moving values ​​instead of copying them. So I made a test program to compare speed with std::vector.

Code:

#include <iostream>
#include <vector>
#include <stdint.h>

#ifdef WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif
#undef max

// Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
// windows and linux.

uint64_t GetTimeMs64()
{
#ifdef _WIN32
    // Windows
    FILETIME ft;
    LARGE_INTEGER li;

    // Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
    // to a LARGE_INTEGER structure.
    GetSystemTimeAsFileTime(&ft);
    li.LowPart = ft.dwLowDateTime;
    li.HighPart = ft.dwHighDateTime;

    uint64_t ret = li.QuadPart;
    ret -= 116444736000000000LL; // Convert from file time to UNIX epoch time.
    ret /= 10000; // From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals

    return ret;
#else
    // Linux
    struct timeval tv;

    gettimeofday(&tv, NULL);

    uint64 ret = tv.tv_usec;
    // Convert from micro seconds (10^-6) to milliseconds (10^-3)
    ret /= 1000;

    // Adds the seconds (10^0) after converting them to milliseconds (10^-3)
    ret += (tv.tv_sec * 1000);

    return ret;
#endif
}

static std::vector<std::string> GetVec1()
{
    std::vector<std::string> o(100000, "abcd");
    bool tr = true;
    if (tr)
        return std::move(o);
    return std::move(std::vector<std::string>(100000, "abcd"));
}

static std::vector<std::string> GetVec2()
{
    std::vector<std::string> o(100000, "abcd");
    bool tr = true;
    if (tr)
        return o;
    return std::vector<std::string>(100000, "abcd");
}

int main()
{
    uint64_t timer;
    std::vector<std::string> vec;

    timer = GetTimeMs64();
    for (int i = 0; i < 1000; ++i)
        vec = GetVec1();
    std::cout << GetTimeMs64() - timer << " timer 1(std::move)" << std::endl;
    timer = GetTimeMs64();
    for (int i = 0; i < 1000; ++i)
        vec = GetVec2();
    std::cout << GetTimeMs64() - timer << " timer 2(no move)" << std::endl;
    std::cin.get();
    return 0;
}

I got the following results:

Release (x86) / O2. tr = true

4376 timer 1 (std :: move)

4191 Timer 2 (no movement)

Release (x86) / O2. tr = false

7311 timer 1 (std :: move)

7301 timer 2 (no movement)

The results between the two timers are really close and actually are not that different. I already assumed that this was due to Return Value Optimization (RVO) , which means that my return values ​​by value are already moved by the compiler if I don't know, right?

So, I ran new tests without any optimizations to make sure I was right. Results:

(x86)/Od. tr = true

40860 1 (std:: move)

40863 2 ( )

(x86)/Od. tr = false

83567 1 (std:: move)

82075 2 ( )

, /O 2 /Od , std::move ( tr true false) .

, , , RVO std::move , , ?

+4
2

, : , return ( , ) -- (, o ), , rval ( ). , , , lvalue. ++ 14 12.8/32; ++ 11.

12.8/32 / , , , , lvalue, return (, ) id-, , -- -, , rvalue. , rvalue (, cv), , lvalue. [. , . , , elision , , . -end note]...

( )

, - , std::move return.

std::move return - , -, . NRVO - " rvalue first".

+9

RVO, /Od. ++ (§12.8/31,32, Kerrek SB)

, volatile. RVO. (§12.8/31, 1)

+4

Source: https://habr.com/ru/post/1609482/


All Articles