Почему не двигать конструктор быстрее? - PullRequest
2 голосов
/ 15 апреля 2019

У меня очень простой тестовый пример с одним Geometry классом, содержащим очень большой std :: vector. Я сравниваю скорость копирования / перемещения конструкторов:

class Geometry
{
public:
    Geometry(size_t size) : m_data(size) {}

    Geometry(const Geometry& other) : m_data(other.m_data)
    { std::cout << "Copy constructor" << std::endl; }

    Geometry(Geometry&& other) noexcept : m_data(std::move(other.m_data))
    { std::cout << "Move constructor" << std::endl; }

private:
    std::vector<double> m_data;
};

int main()
{
    Geometry geometry(1000000000);

    {
        ScopedTimer scopedTimer("copy constructor");
        Geometry geometry2(geometry);
    }

    {
        ScopedTimer scopedTimer("move constructor");
        Geometry geometry2(std::move(geometry));
    }
}

Я ожидал, что конструктор копирования будет очень медленным, а конструктор перемещения будет практически мгновенным, поскольку ему просто нужно поменять дескриптор на базовые векторные ресурсы. Однако это не то, что я наблюдаю здесь (ScopedTimer - это простой таймер, основанный на std :: chrono, который возвращает время между его созданием и уничтожением). Вот выходные данные, которые я получаю в конфигурации выпуска (аналогичная тенденция наблюдается в конфигурации отладки):

Copy constructor
6832 ms copy constructor
Move constructor
2605 ms move constructor

Конструктор Move примерно в три раза быстрее, что лучше, но не то, что я ожидал. Почему не быстрее, чем это? Я ожидал, что конструктор перемещения будет O (1). Почему это занимает больше времени с большими размерами вектора? Код не должен ничего выделять и т. Д. Я что-то упустил?

1 Ответ

2 голосов
/ 15 апреля 2019

Вы измеряете время разрушения вектора. Без этого конструктор перемещения не требует времени даже в режиме отладки:

#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <chrono>

class ScopedTimer
{
    std::string m_text;
    ::std::chrono::high_resolution_clock::time_point start;
    public: ScopedTimer(::std::string const & text):
    m_text{text}, start{::std::chrono::high_resolution_clock::now()} {}

    public: void Report(void)
    {
        auto const end{::std::chrono::high_resolution_clock::now()};
        ::std::cout << m_text << " " << ::std::chrono::duration_cast<::std::chrono::milliseconds>(end - start).count() << ::std::endl;
    }
};


class Geometry
{
public:
    Geometry(size_t size) : m_data(size) {}

    Geometry(const Geometry& other) : m_data(other.m_data)
    { std::cout << "Copy constructor" << std::endl; }

    Geometry(Geometry&& other) noexcept : m_data(std::move(other.m_data))
    { std::cout << "Move constructor" << std::endl; }

private:
    std::vector<double> m_data;
};

int main()
{
    Geometry geometry(1000000000);
    {
        ScopedTimer scopedTimer("copy constructor");
        {
            Geometry geometry2(geometry);
            scopedTimer.Report();
        }
        scopedTimer.Report();
    }
    {
        ScopedTimer scopedTimer("move constructor");
        {
            Geometry geometry2(std::move(geometry));
            scopedTimer.Report();
        }
        scopedTimer.Report();
    }
    return 0;
}

Конструктор копирования
конструктор копирования 5099
конструктор копирования 6526
Переместить конструктор
переместить конструктор 0
переместить конструктор 1319

...