прохождение тяжелых объектов C++0x

У меня есть функция, которая создает тип дорогого объекта (содержащего векторы и карты нефиксированного размера), поэтому я действительно хочу избежать вызова копирования c'tors.

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

Я знаю две вещи, которые могут мне помочь. Во-первых, копирование elision, а во-вторых, семантика движения.

Моя проблема в том, что я не знаю, как правильно использовать ни то, ни другое. Мое исследование показало мне, что исключение копирования полностью выполняется компилятором и не является частью стандартного. Я действительно не хочу полагаться исключительно на это.

Итак, как я могу гарантировать, что назначение перемещения вызывается и имеет его на месте, чтобы компилятор не мог копировать elision.

ResultSet &&generateResults()
{
    //ResultSet a(); :S
    ResultSet a;
    a.populat(...
    //blah blah blah
    return a;
}

//else where (where the && assignment operator is overloaded
ResultsSet b = generateResults();

В этом случае это самый правильный способ закодировать это? и если нет, как я могу улучшить его. Я рад использовать только конструкции C++0x.

Кстати: мой компилятор gcc 4.6


person 111111    schedule 18.06.2011    source источник
comment
@Tom'... ну, я хотел бы конкретизировать: D   -  person 111111    schedule 18.06.2011


Ответы (5)


Если вам не нравится читать, вот ссылка на видео о rvalue и семантике перемещения: http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-9-of-n

person engf-010    schedule 18.06.2011
comment
Я не против читать, просто когда ВСЕ новое, я чувствую, что многого не усваиваю. Я обязательно посмотрю это видео сейчас. :D - person 111111; 18.06.2011
comment
@111111: Вы должны посмотреть другие видео из этой серии, они очень информативны. - person engf-010; 18.06.2011
comment
что эти видео очень информативны, и парень, делающий их, довольно забавный, «если вы помните auto_prt, забудьте их». - person 111111; 18.06.2011
comment
@111111: Если вы предпочитаете читать информацию (я знаю, что мне гораздо проще ее обрабатывать), см. эту запись в блоге того же автора: blogs.msdn.com/b/vcblog/archive/2009/02 /03/ Трудно вырезать+вставить и самому попробовать примеры, если это просто картинки на видеоэкране. - person Ben Voigt; 18.06.2011

Хороший ответ на ваши вопросы можно найти в этой серии сообщений в блоге Дэйва Абрахамса:

http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

Он охватывает взаимодействие между ссылками rvalue, конструкторами перемещения и копированием. Это немного длинно, но это стоит того, чтобы прочитать все это :)

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

person bluescarni    schedule 18.06.2011
comment
Я прочитал это и сопутствующую статью. Но я все еще остался с вышеуказанным вопросом. Я должен указать, что я был C++ всего несколько месяцев (от ansi C). Я уверен, что вы можете оценить, что есть чему поучиться, я просто хочу делать это правильно с самого начала, а не выбрасывать код, который я пишу сейчас, через пару лет. - person 111111; 18.06.2011
comment
Итак, если то, что вы говорите, верно, я не должен помещать && в возвращаемый тип, а компилятор сделает все остальное? - person 111111; 18.06.2011
comment
@ 111111 Да, вы должны удалить && в возвращаемом типе. В противном случае вы вернете висячую ссылку. - person bluescarni; 18.06.2011

В этом случае это самый правильный способ закодировать это?

На самом деле это "наименее правильный" способ: вы возвращаете ссылку на автоматический объект. Когда функция возвращается, клиент получает ссылку на объект, которого больше не существует.

В этом отношении нет никакой разницы между ссылками lvalue и ссылками rvalue. Так что просто избавьтесь от ссылки rvalue и верните результат по значению. Вы либо получите NRVO, либо переместите семантику.

person fredoverflow    schedule 19.06.2011

Ваше исследование ошибочно. Копирование абсолютно стандартно. Это не обязательно, но официально разрешено. В примере с вашей функцией я бы определенно ожидал, что она будет применена, поскольку преобразование относительно тривиально.

А во-вторых, вы не должны возвращать ссылку rvalue — просто возвращайте по значению. Компилятор не обязан исключать копию — хотя, вероятно, все же будет, — но он должен вызывать семантику перемещения.

О, и вам нужно перегрузить конструктор перемещения, не оператор присваивания перемещения, для этого конкретного фрагмента кода, хотя, конечно, в идеале вы должны сделать и то, и другое.

ResultSet a();

Не определяет никакой переменной, но объявляет функцию с именем a, ничего не принимающую и возвращающую ResultSet.

person Puppy    schedule 18.06.2011
comment
извините, что был неправ в моем примере. Я знаю, что я просто забыл, что в моем фактическом вопросе ему передаются параметры, но они не касаются этого вопроса. «О, и вам нужно перегрузить конструктор перемещения», вы имеете в виду, что это должен быть ResultSet b(generateResults()); Спасибо, кстати. - person 111111; 18.06.2011
comment
@ 111111: Код в вашем вопросе - это copy-initialization (и использует конструктор перемещения, если он доступен, конструктор копирования в противном случае), ни один из них не использует оператор присваивания. В вашем комментарии используется прямая инициализация, когда типы совпадают, она работает точно так же. Пример, в котором используется оператор присваивания: ResultSet b; b = generateResults(); Обратите внимание, что присваивание теперь полностью отделено от построения объекта. - person Ben Voigt; 18.06.2011
comment
@ 111111: Нет, я имею в виду, что разница между ResultSet b(generateResults()); и ResultSet b = generateResults(); абсолютно ничтожна - они оба вызывают конструктор перемещения, ResultSet::ResultSet(ResultSet&&)- не ResultSet::operator=(ResultSet&&). - person Puppy; 18.06.2011
comment
круто, теперь я тебя понял. благодаря. Я ошибочно думал, что он потом построит init'. - person 111111; 18.06.2011
comment
@111111: назначение — это не то же самое, что инициализация. И синтаксис type var = value; - это инициализация, а не присваивание. - person Ben Voigt; 18.06.2011

Вы можете узнать о конструкторах перемещения, и я уверен, что кто-нибудь предоставит пример для вас.

Но можно рассмотреть и другой вариант: unique_ptr. Для вашего приложения он должен работать так же хорошо, как и shared_ptr, и значительно эффективнее. (Однако вам могут понадобиться эти определения типов.)

person Nemo    schedule 18.06.2011
comment
это. Я не был уверен, как безопасно вернуть unique_ptr, просто вернуть uptr или вернуть move(uptr); но на самом деле я хотел бы, чтобы RVO и C-Elison работали, поскольку они производят самый чистый код, который я чувствую - person 111111; 18.06.2011