Какие коды должны знать ссылки на rvalue?
Я вижу, что у многих людей возникают проблемы с пониманием ссылок на rvalue. Будет ли "обычный" С++-код (например, который использует стандартную библиотеку, но не реализует его), должен знать о ссылках rvalue после выхода нового стандарта или могут ли люди/код просто притворяться, что ссылки rvalue не существуют? Ссылки rvalue в первую очередь касаются разработчиков библиотек или всех программистов?
Ответы
Ответ 1
Я ничего не видел, чтобы не согласиться с этой статьей в блоге GMan (aka gmannickg):
http://blackninjagames.com/?p=95
Сводка: любой, кто знает о copy-and-swap (и вообще правило три), должен знать о семантике перемещения (и, следовательно, ссылки на rvalue), потому что в результате меняются лучшие идиомы. Поэтому я думаю, что любой, кто вообще заботится о С++.
Я не думаю, что вам нужно знать, потому что, конечно, копирование и своп все еще работает, оно по-прежнему исключение и т.д. И я полагаю, кто-то может спорить о том, нужен ли "обычный" код и программисты на С++, чтобы узнать "копировать и сменять". Я надеюсь, что ответ "ну, ну, очевидно", но вы никогда не знаете.
Конечно, точка, с которой можно начинать использовать С++ 0x, будет варьироваться от места к месту. Вероятно, неплохо было бы отменить С++ 03 в ближайшее время.
Например, возврат огромных коллекций по значению в контекстах, которые недействительны для копирования, является лучшей ставкой, если вы можете положиться на назначение перемещения. Это не случай чего-то, что недействительно в С++ 03 становится действительным в С++ 0x, это код, который ужасно замедляется в С++ 03, который вы обойдете (даже если только с хорошо размещенным swap
), становясь прекрасным в С++ 0x. Поэтому, если вы притворяетесь, что ссылки rvalue не существуют, вы будете продолжать работать над тем, что вам не нужно. Если вы сделаете прыжок, он может аккуратно вернуться к С++ 03, но запустить собаку медленно, что является болью.
Таким образом, умная вещь может быть связана с ней, и во многих контекстах притворяется, что ее не существует.
Ответ 2
По крайней мере, для большинства ситуаций вы можете игнорировать их примерно столько, сколько захотите. (Re), записывающие стандартную библиотеку для их использования, позволяют значительно оптимизировать и некоторые новые возможности, но одна из основных целей заключается в том, что существующий код должен продолжать работать отлично (хотя в некоторых случаях быстрее).
Поддержка существующего кода подразумевает, что любой, кто чувствует себя так, может продолжать писать код так же, как и раньше, и не подвергаться воздействию (опять же, за исключением того, что некоторые "вещи" библиотеки, которые они используют, могут быть быстрее).
В то же время есть некоторые довольно веские причины, по которым кто-то может захотеть изучить хотя бы несколько эмпирических правил, которые позволяют им просто использовать ссылки rvalue. Одним из очевидных примеров может быть проблема, с которой люди регулярно сталкиваются: у них есть класс, который на самом деле не имеет смысла копировать объекты, но они все равно хотели бы поместить эти объекты в коллекцию (например, вектор).
Они могут сделать это, сделав объекты этого класса подвижными, но не скопируемыми. Ярким примером этого будет поток - прямо сейчас вы не можете поместить какой-либо объект iostream в коллекцию, но в С++ 0x вы сможете.
Другая возможность - использовать "совершенную переадресацию". Это может упростить консолидацию того, что раньше было бы несколькими отдельными функциями в одном с действительно тривиальными интерфейсами, которые все переходят к тому, что делает реальную работу. Вы всегда можете обойтись без этого, но в некоторых случаях это может сделать код довольно немного менее повторяющимся.
Ответ 3
Большинство людей могут просто притворяться, что их нет, и они просто видят преимущества (более быстрый код в некоторых случаях).
Помните, что С++ 0x будет совместим с 99,9% назад, поэтому весь существующий код все равно будет работать, что означает, что вы можете продолжать писать код С++ 0x, как если бы это был С++ 03.
Если вы хотите воспользоваться преимуществами ссылок rvalue, тогда, конечно, вам нужно будет узнать о них, но большую часть времени это будет только проблемой библиотек.
Ответ 4
Возможно, вам не нужно знать о ссылках rvalue в смысле написания какой-либо функции, которая берет одну, но вы можете извлечь выгоду из понимания семантики перемещения, зная, что такое конструктор перемещения, и так далее. Если вы хотите использовать unique_ptr (и получить выгоду от перфоманса, поскольку у нее нет счетной ссылки), вам почти наверняка придется использовать std:: move (скажем, в коллекцию и из коллекции), и я не могу представить, чтобы это приближалось к тому, что в "что, если я положил a или или здесь?" что типичный студент второго курса справляется с указателями.
Я только что сделал "что нового в VС++ с участием С++ 0x" в Tech Ed Europe в Берлине, где был один слайд на ссылках на rvalue, и я в основном сказал: "Вам нужно знать, что они здесь, потому что они делают STL быстрее", но я еще не тренировал. Участники, которые, по-видимому, были лучше восприняты, чем варианты (более длинные), которые я имел в других беседах.
Ответ 5
Я согласен, что RValue References - это не всякая чашка чая - чашка довольно большая.
Из-за этого я рассказываю учащимся С++ 0x, что лучший подход к началу работы и использование RValue References - это использовать STL и охватывать его шаблоны проектирования со временем. Очень вероятно, что благодаря этому вы получаете выгоду от ссылок RValue, не понимая их полностью заранее.
Ответ 6
Скотт Майерс разделил функции С++ 0x на:
- Возможности для всех.
- Особенности для авторов классов.
- Возможности авторов библиотеки.
RValues - это, безусловно, авторы библиотек.
Ответ 7
В С++ 11 я бы передал все, что я планирую "хранить" или "потреблять" с помощью & &. Это приводит к наиболее эффективному коду, но "ломает" lvalue-совместимость и заставляет меня учитывать наличие двух (или более) версий каждого метода. К сожалению, вы получаете взрыв перестановок rvalue и const & поскольку количество аргументов увеличивается, и это делает получение указателей функций намного более "уродливым".
Вместо предоставления двух (или более) перегрузок, один для lvalues и один для rvalue, я решил предоставить только перегрузку rvalue, и если пользователь хочет передать lvalue, они обертывают std:: ref(), std:: cref(), std:: move() или моя собственная вспомогательная копия(), которая делает копию явной и преобразует значение lvalue в значение r. (std:: ref() и std:: cref() могут работать, только если аргументы являются параметрами шаблона... в этом случае метод, вероятно, будет использовать std:: forward < > () для обработки автоматического обнаружения перемещения vs copy semantics.
template<typename T>
T copy( const T& v ) { return v; }
Если я пишу метод, который не "хранит" или "потребляет" вход, я использую const &
Я должен, вероятно, уточнить, что я буду использовать const & для любых типов, которые не используют семантику перемещения (без глубоких копий). Но когда вы пишете код шаблона, вы не хотите делать это предположение о типе.
Другая практика, которую я рассматриваю, - это сделать только явные копии определенных классов.
class test {
public:
test(){...};
test( test&& t ){...}
private:
template<typename T>
friend T copy(const T&t);
test& operator=(const test&); // not implemented
test( const test& t ){...}
std::vector<char> large_data;
};
int main( int argc, char** argv ) {
test x;
test y = copy(x);
test z = x; // error, test(const test&) is private...
return 0;
}
Я бы использовал это для любого класса, который содержит любые "подвижные члены", такие строки, векторы, карты и т.д. Технически нет причин, по которым я не мог их скопировать, но почему бы мне не попробовать семантику перемещения везде, если я действительно хочу скопировать? С неявными копиями компилятор не может предупредить меня, что я делаю что-то потенциально дорогое.
Ответ 8
Если вы не внедряете класс семантики значения, вам действительно не нужно знать.
Изменить: или идеальная переадресация. Но это в основном использует библиотека.