C ++ 11 способ инициализации членов данных из аргументов - PullRequest
20 голосов
/ 21 августа 2011

Поскольку C ++ 11 поддерживает семантику перемещения, при инициализации членов данных из аргументов, следует ли нам пытаться перемещать значение вместо его копирования?

Вот пример, показывающий, как бы я подошел к этому в пре-C ++ 11:

struct foo {
    std::vector<int> data;

    explicit foo(const std::vector<int>& data)
        : data(data)
    {
    }
};

Здесь будет вызван конструктор копирования.

В C ++ 11 мы должны привыкнуть писать так:

struct foo {
    std::vector<int> data;

    explicit foo(std::vector<int> data)
        : data(std::move(data))
    {
    }
};

Здесь будет вызываться конструктор перемещения ... и конструктор копирования, если переданный аргумент является lvalue, но преимущество состоит в том, что если передано значение r, конструктор перемещения будет вызываться вместо копирующего .

Мне интересно, есть ли что-то, чего мне не хватает.

Ответы [ 4 ]

8 голосов
/ 21 августа 2011

Мой первоначальный ответ на ваш вопрос был:

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

explicit foo(std::vector<int>&& data)
    : data(std::move(data))            // thanks to Kerrek SB
{
}

Не совсем соответствует вашему вопросу, но чтение Правило-три становится Правило-пять с C ++11? представляется полезным.

Редактировать:

Однако принят ответ на Передача / перемещение параметров конструктора в C ++ 0x , кажется, поддерживает ваш подход, особенно с более чем одним параметром.В противном случае произошел бы комбинаторный взрыв вариантов.

3 голосов
/ 21 августа 2011

Да, вы делаете это правильно.Каждый раз, когда вам нужна копия значения, делайте это в параметрах, передавая значение.

Следующее верно:

struct foo {
    std::vector<int> data;

    explicit foo(std::vector<int> data)
        : data(std::move(data))
    {
    }
};
3 голосов
/ 21 августа 2011

Передача по значению в конструкторе копирования помогает только тогда, когда аргумент является подвижным, в противном случае вы можете получить до двух копий (одну для передачи аргумента, одну для конструкции члена).Поэтому я бы сказал, что лучше написать копию и конструктор перемещения отдельно.

Передача по значению имеет смысл для оператора присваивания, если у вас правильно реализована функция swap, хотя:

Foo & operator=(Foo other) { this->swap(std::move(other)); }

Теперь, если other является подвижным, конструктор перемещения Foo входит во время создания аргумента, а если other просто копируется, то одна необходимая копия создается во время создания аргумента, но в обоих случаях выиспользовать движущуюся версию swap, которая должна быть дешевой.Но это зависит от существования конструктора перемещения!

Так что обратите внимание, что из «конструкции», «свопа» и «назначения» вам придется правильно реализовать два, и только третий может воспользоваться преимуществамидругие два.Поскольку swap должен быть безбросковым, использование трюка подкачки в операторе присваивания является в основном единственным вариантом.

0 голосов
/ 21 августа 2011

Вы должны придерживаться:

struct foo {
    std::vector<int> data;

    explicit foo(const std::vector<int>& data)
        : data(data)
    {
    }
};

. В этом случае "копируются только данные".

Во втором случае:

struct foo {
    std::vector<int> data;

    explicit foo(std::vector<int> data)
        : data(std::move(data))
    {
    }
};

"данные"сначала копируется , а затем перемещается .Что дороже, чем просто копирование.Помните, что перемещение не является бесплатным, даже если оно, вероятно, намного дешевле, чем копирование.

С другой стороны, вы можете добавить следующее (в дополнение или вместо первого).

struct foo {
    std::vector<int> data;

    explicit foo(std::vector<int>&& data)
        : data(std::move(data))
    {
    }
};

Где вы знаете, что «данные» не будут использоваться после вызова конструктора, и в этом случае вы можете просто переместить его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...