Your SlideShare is downloading. ×
0
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
C++ 2: R-value, move semantics
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

C++ 2: R-value, move semantics

527

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
527
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Лекция 3. Move семантика и Rvalue reference Valery Lesin. C++ In-Depth, 2014 1
  • 2. Быстрые программы • Программы на C++ ценят за их скорость Valery Lesin. C++ In-Depth, 2014 2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. string inverted(string const& str) { if (str.empty()) return string(); string tmp(str); size_t beg = 0; size_t end = tmp.size() - 1; while(beg < end) swap(tmp[beg++], tmp[end--]); return tmp; } //... string a = "olleH"; a = inverted(a); • И сколько же дополнительных копирований строки?
  • 3. Быстрые программы • Программы на C++ ценят за их скорость Valery Lesin. C++ In-Depth, 2014 3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. string inverted(string const& str) { if (str.empty()) return string(); string tmp(str); size_t beg = 0; size_t end = tmp.size() - 1; while(beg < end) swap(tmp[beg++], tmp[end--]); return tmp; } //... string a = "olleH"; string b = inverted(a); • Три (или два при RVO) • Как избежать копирования из разрушающегося объекта?
  • 4. Lvalue vs Rvalue • Lvalue – выражение, описывающее объект, живущий дольше самого выражения (мнемоника: то, что может быть по левую сторону от ‘=’). • Rvalue – выражение, описывающее временный объект (мнемоника: то, что может быть по правую сторону от ‘=’). Valery Lesin. C++ In-Depth, 2014 4
  • 5. Lvalue vs Rvalue. Примеры Valery Lesin. C++ In-Depth, 2014 5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. // L-value string answ = "42"; answ = "13"; //... int& answer_ref() {return answ;} answer_ref() = "7";
  • 6. Lvalue vs Rvalue. Примеры Valery Lesin. C++ In-Depth, 2014 6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. // L-value string answ = "42"; answ = "13"; //... string& answer_ref() {return answ;} answer_ref() = "7"; // R-value string answer() { string answ = "7"; return good_day() ? answ : "13"; } string const& a = answer(); // works fine string& b = answer(); // nope! answer() = "13"; // nope!
  • 7. Как отличить временный объект от невременного • Rvalue reference Valery Lesin. C++ In-Depth, 2014 7 • Такая ссылка крайне полезна при перегрузке 1. string&& a = answer(); // compiled, but rare code 1. 2. string low_case(string const& s); // need copy string low_case(string&& s); // need no copy
  • 8. Move constructor Valery Lesin. C++ In-Depth, 2014 8 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. // copy constructor string(string const& other) : buf_ (new char[other.size() + 1]) // buf_ is 'char*' , size_(other.size()) { strcpy(buf_, other.buf_); }
  • 9. Move constructor Valery Lesin. C++ In-Depth, 2014 9 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. // copy constructor string(string const& other) : buf_ (new char[other.size() + 1]) // buf_ is 'char*' , size_(other.size()) { strcpy(buf_, other.buf_); } // move constructor, no need to copy in ‘string s = answer()’ string(string&& other) : buf_ (other.buf_ ) // stealing pointer , size_(other.size()) { other.buf_ = nullptr; other.size_ = 0; }
  • 10. Move constructor Valery Lesin. C++ In-Depth, 2014 10 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. // copy constructor string(string const& other) : buf_ (new char[other.size() + 1]) // buf_ is 'char*' , size_(other.size()) { strcpy(buf_, other.buf_); } // move constructor, no need to copy in ‘string s = answer()’ string(string&& other) : buf_ (other.buf_ ) // stealing pointer , size_(other.size()) { other.buf_ = nullptr; other.size_ = 0; } // move constructor via delegating and swap (*) string(string&& other) : string() // default constructor { swap(other); }
  • 11. Move assignment operator Valery Lesin. C++ In-Depth, 2014 11 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. // swap trick string& operator=(string const& other) { string tmp(other); swap(tmp); return *this; }
  • 12. Move assignment operator Valery Lesin. C++ In-Depth, 2014 12 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. // swap trick string& operator=(string const& other) { string tmp(other); swap(tmp); return *this; } // extended swap trick gives // copy and move ‘op=’ at the same time string& operator=(string other) { swap(other); return *this; }
  • 13. Rvalue reference – Rvalue? • Что, если поле имеет пользовательский тип? Valery Lesin. C++ In-Depth, 2014 13 1. 2. 3. 4. string(string&& other) : buf_(other.buf_) // buf_ is 'vector<char>' { // doesn’t work as expected } 1. 2. 3. 4. 5. 6. 7. void foo(T const& t) { // has overloadings for T const& and T&& bar(t); // (1) //... // has overloadings for T const& and T&& qux(t); // (2) } • Здесь Rvalue reference – не Rvalue, т.к. указывает на именованный невременный объект. • Если бы t был rvalue, то смена прототипа функции foo принципиально меняла бы ее логику – вероятно, было бы падение в (2).
  • 14. std::move • Как объяснить компилятору, что объект все-таки rvalue? • move не ‘перемещает’ объект, а только изменяет его тип. Valery Lesin. C++ In-Depth, 2014 14 1. 2. 3. 4. 5. 6. 7. 8. 9. template< class T > typename std::remove_reference<T>::type&& move(T&& t); //... string(string&& other) : buf_(std::move(other.buf_)) // buf_ is 'vector<char>' { // now works fine! }
  • 15. Move constructor vs other constructors • Move семантика является родной для RAII – Копирование часто невозможно, а передача владение допустима. – Пример: std::unique_ptr • Move конструктор ‘выключает’ автоматическую генерацию других конструкторов (но не в MSVC), но в С++11 есть удобный прием: Valery Lesin. C++ In-Depth, 2014 15 1. 2. 3. 4. 5. 6. struct data { data() = default; data(data&& other){/*...*/} //... };
  • 16. Возврат из функции значения vs && • Rvalue reference – лишь ссылка. Вернув ее на временный объект, получите undefined behavior. • Возвращайте значение! Контринтуитивно, да? Move семантика обеспечит ‘условно бесплатное’ копирование. • Можно вернуть && на поле (как и обычную ссылку). Но тогда удаление поля будет зависеть от контекста вызова. Почему? Valery Lesin. C++ In-Depth, 2014 16
  • 17. Нужен ли теперь swap(T&, T&)? • Если ваш класс обладает move семантикой, то нет необходимости реализовывать отдельный swap для него – подойдет обобщенный. Valery Lesin. C++ In-Depth, 2014 17 1. 2. 3. 4. 5. 6. 7. template<class T> void swap(T& lhs, T& rhs) { T tmp = move(lhs); lhs = move(rhs); rhs = move(tmp); }
  • 18. Преобразование & <-> const & <-> && • Можно вызвать для Lvalue, но не для Rvalue. Valery Lesin. C++ In-Depth, 2014 18 1. 2. implemented : void foo(T&); not implemented: void foo(T&&); 1. 2. implemented : void foo(T const&); not implemented: void foo(T&&); 1. 2. 3. implemented : void foo(T&&); not implemented: void foo(T&); not implemented: void foo(T const&); • Можно вызвать для Lvalue и для Rvalue, но нельзя их отличить. • Можно вызвать для Rvalue, а вот вызов для Lvalue даст compile error.
  • 19. Perfect forwarding (*) • В пример с функцией inverted по-прежнему осталось лишнее копирование при передаче параметра. Что делать? Valery Lesin. C++ In-Depth, 2014 19 1. 2. 3. 4. 5. 6. 7. 8. template<class string_t> string inverted(string_t&& str) { string tmp(std::forward<string_t>(str)); //... // or even much easier string inverted(string str); • Вызов inverted(str) приведет к копированию, inverted(move(str)) – к перемещению. • Функция std::forward крайне полезна для variadic templates. • Поможет с конструктором?
  • 20. Вопросы? Valery Lesin. C++ In-Depth, 2014 20

×