Почему конструкторы копирования и перемещения оказываются в одинаковом количестве мемкопий? - PullRequest
0 голосов
/ 29 октября 2019

Здесь проблема состоит в том, чтобы понять, был ли вызван конструктор копирования или перемещения при инициализации вектора возвращаемым объектом функции. Проверка malloc с помощью профилировщика показывает одинаковые memcopies в обоих случаях. Почему?

У нас есть класс типа «сообщение». Класс предоставляет функцию «data_copy», которая возвращает содержимое «сообщения» в виде вектора.

Есть 2 варианта, которые я пробовал. Один из них - использовать непосредственно конструктор копирования для инициализации нового вектора.

std::vector<uint8_t> vector1 ( message.data_copy() );

Второй вариант - попытаться избежать дополнительной копии и выполнить

std::vector<uint8_t> vector1 ( std::move( message.data_copy() ) );

. data_copy () делает.

std::vector<uint8_t> message::data_copy(void) const
{
    std::vector<uint8_t> d(this->size());
    copy_data_to_buffer(d.data());
    return d;
}
void message::copy_data_to_buffer(uint8_t* buffer) const
{
    DEBUG_LOG("copy_data_to_buffer");
    for(const fragment* p = &head; p != nullptr; p = p->next)
    {
        memcpy(buffer, p->data[0], p->size[0]);
        buffer += p->size[0];

        if(p->size[1])
        {
            memcpy(buffer, p->data[1], p->size[1]);
            buffer += p->size[1];
        }
    }
}

Наконец, с помощью профилировщика я сравниваю количество вызовов malloc. Хотя можно было бы ожидать, что конструктор перемещения позволит избежать дополнительной копии в действительности, в обоих случаях они одинаковы.

1 Ответ

4 голосов
/ 29 октября 2019

Вы используете конструктор перемещения оба раза. Результат data_copy является временным. Затем вы создаете vector с этим временным аргументом. Итак, это ход.

Во второй раз вы в основном приводите объект, который уже является ссылкой rvalue, на ссылку rvalue, и поэтому конструктор перемещения используется снова. Не должно быть абсолютно никакой разницы между поведением их обоих.

Я думаю, может быть, вы неправильно понимаете, что такое временное и что такое ссылка на значение. Не часто вам приходится использовать ::std::move, и если вы его используете, вы должны внимательно посмотреть на код, в котором вы его используете, чтобы убедиться, что вы делаете правильные вещи.

Этот код наGodbolt является доказательством того, что конструктор копирования никогда не называется . Вот код, на который ссылаются:

#include <utility>

struct ICantBeCopied {
    ICantBeCopied(ICantBeCopied const &) = delete;
    ICantBeCopied(ICantBeCopied &&) {}
    ICantBeCopied() {}
};

ICantBeCopied make_a_copy()
{
    ICantBeCopied c;
    return c;
}

void a_function()
{
    ICantBeCopied a{make_a_copy()};
    ICantBeCopied b{::std::move(make_a_copy())};
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...