SlideShare a Scribd company logo
C++ references
CoreHard Winter 2017
My name is Gavrilovich Yury =)
Objective
● Overview of “ancient” C++11 feature: rvalue references
● Leave in your memory not numerous details but
high-level ideas!
● Inspire to get profound understanding by yourselves!
(Homework presents)
For those who is not aware of:
● Rvalue references (&&)
● Forwarding (universal) references
● Move semantics
● Perfect forwarding
lvalues vs
rvalues
Short reminder:
“what’s the difference”
with examples
rvalue
references
What is it? The
purpose?
move
semantics
Move ctors,
std::move()
The problem
forwarding
references
briefly
&& is not only rvalue
reference
perfect
forwarding
briefly
lvalues vs
rvalues
rvalue
references
move
semantics
forwarding
references
briefly
perfect
forwarding
briefly
Formal definition from C++ standard
Informal definition (good enough)
● If you can take the address of an expression, the expression is an
lvalue
● If the type of an expression is an lvalue reference (e.g., T& or const
T&, etc.), that expression is an lvalue
● Otherwise, the expression is an rvalue. (Examples: temporary objects,
such as those returned from functions or created through implicit type
conversions. Most literal values (e.g., 10 and 5.3))
Homework #1
● Function parameters (not arguments) are lvalues
● The type of an expression is independent of whether the expression is an
lvalue or an rvalue. That is, given a type T, you can have lvalues of type T
as well as rvalues of type T. [Effective Modern C++. Introduction]
lvalue examples
(can take address)
int i = 13; // i is lvalue
int* pi = &i; // can take address
int& foo();
foo() = 13; // foo() is lvalue
int* pf = &foo(); // can take address
int i = 14;
int& ri = i; // ri is lvalue
int* pri = &ri; // can take address
lvalue examples
(can take address)
template <typename T>
T& MyVector::operator[] (std::size_t const n);
MyVector<int> v{1,3,5,7};
v[0] = 2; // v[0] is lvalue
int* pv = &v[0]; // can take address
rvalue examples
(can NOT take address)
int i = 13; // 13 is rvalue
i += 1; // 1 is rvalue
yury.gavrilovich@yurys-Mac ~/$ objdump -d -x86-asm-syntax=intel
a.out
mov dword ptr [rbp - 8], 13
mov ecx, dword ptr [rbp - 8]
add ecx, 1
rvalue examples
(can NOT take address)
a + b = 3; // error: lvalue required as
left operand of assignment
int bar(); // bar() is rvalue
bar() = 13; // error: expression is not
assignable
int* pf = &bar(); // error: cannot take the
address of an rvalue of type 'int'
struct X{};
X x = X(); // X() is rvalue
X* px = &X(); // error: taking the address
of a temporary object of type 'X'.
Question for your
understanding:
const int i = 1;
rvalue or lvalue??
move
semantics
forwarding
references
briefly
perfect
forwarding
briefly
lvalues vs
rvalues
rvalue
references
lvalue references (&)
X x;
X& lv = x;
X& lv2 = X(); // error: non-const lvalue reference to
type 'X' cannot bind to a temporary of type 'X'
X const& lv3 = X(); // OK, since const&
rvalue references (&&)
X x;
X&& rv2 = x; // error: rvalue reference to type 'X' cannot bind
to lvalue of type 'X'
X&& rv = X(); // OK
rvalue references (&&)
rvalue references is a small technical extension to the C++ language. Rvalue
references allow programmers to avoid logically unnecessary copying and to
provide perfect forwarding functions. They are primarily meant to aid in the
design of higher performance and more robust libraries.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
“A Brief Introduction to Rvalue References”
Document number: N2027=06-0097
Howard E. Hinnant, Bjarne Stroustrup, Bronek Kozicki
2006-06-12
Besides resolving aforementioned problems
Rvalue references allow branching at compile time:
void foo(int& a); // lvalue reference overload
void foo(int&& a); // rvalue reference overload
int a = 1;
int bar();
foo(a); // argument is lvalue: calls foo(int&)
foo(bar()); // argument is rvalue: calls foo(int&&)
forwarding
references
briefly
perfect
forwarding
briefly
lvalues vs
rvalues
rvalue
references
move
semantics
Our Vector class
template <typename T>
class Vector
{
public:
explicit Vector(std::size_t const size);
~Vector();
Vector(Vector const& other);
Vector& operator= (Vector const& rhs);
// ...
// ...
private:
std::size_t m_size;
T* m_data;
};
Vector class. Constructor, Destructor
template <typename T>
Vector<T>::Vector(std::size_t const size) :
m_size(size),
m_data(new T[size])
{
std::cout << this << " ctor" <<
std::endl;
};
template <typename T>
Vector<T>::~Vector()
{
std::cout << this << " ~dtor" << std::endl;
delete[] m_data;
}
Vector class. Naive implementation (1-3 problems at least)
template <typename T>
Vector<T>::Vector(Vector const& other) :
m_size(other.m_size),
m_data(new T[m_size])
{
std::cout << this << " copy ctor" <<
std::endl;
std::cout << this << "t copying data into
allocated memory" << std::endl;
std::copy(other.m_data, other.m_data + m_size,
m_data);
}
template <typename T>
Vector<T>& Vector<T>::operator= (Vector const& rhs)
{
std::cout << this << " copy assignment operator" <<
std::endl;
if (this == &rhs)
{
return *this;
}
std::cout << this << "t removing old data" <<
std::endl;
delete[] m_data;
m_size = rhs.m_size;
std::cout << this << "t allocating and copying
data" << std::endl;
m_data = new T[rhs.m_size];
std::copy(rhs.m_data, rhs.m_data + m_size, m_data);
return *this;
}
C++ exception safety levels (wikipedia)
1) No-throw guarantee, also known as failure transparency
2) Strong exception safety, also known as commit or rollback
semantics
3) Basic exception safety, also known as a no-leak guarantee
4) No exception safety: No guarantees are made.
A better implementation (copy_and_swap idiom - strong exception guarantee)
template <typename T>
Vector<T>::Vector(Vector const& other) :
m_size(other.m_size),
m_data(new T[m_size])
{
std::cout << this << " copy ctor" <<
std::endl;
std::cout << this << "t copying data
into allocated memory" << std::endl;
std::copy(other.m_data, other.m_data +
m_size, m_data);
}
template <typename T>
Vector<T>& Vector<T>::operator= (Vector const& rhs)
{
std::cout << this << " copy assignment operator"
<< std::endl;
Vector<T> tmp(rhs);
std::swap(m_size, tmp.m_size);
std::swap(m_data, tmp.m_data);
return *this;
}
The problem
Vector<int> v1(1000);
Vector<int> v2(1);
v2 = v1; // Reasonable copy, since v1 is
lvalue
v2 = Vector<int>(2); // Unnecessary copy
template<typename T>
Vector<T> CreateVector(std::size_t const n);
v2 = CreateVector<int>(3); // Either
unnecessary copy
Problem example
Vector<int> v3(1000);
std::cout << "== create temporary in place" << std::endl;
v3 = Vector<int>(2);
std::cout << "== creating temporary through return value"
<< std::endl;
v3 = CreateVector<int>(1000);
yury.gavrilovich@yurys-Mac ~/ $ clang++ -std=c++11 04.cc && ./a.out
0x7fff583cb3c8 ctor
== create temporary in place
0x7fff583cb3a8 ctor
0x7fff583cb3c8 copy assignment operator
0x7fff583cb310 copy ctor
0x7fff583cb310 allocating and copying data
0x7fff583cb310 ~dtor
0x7fff583cb3a8 ~dtor
== creating temporary through return value
0x7fff583cb398 ctor
0x7fff583cb3c8 copy assignment operator
0x7fff583cb310 copy ctor
0x7fff583cb310 allocating and copying data
0x7fff583cb310 ~dtor
0x7fff583cb398 ~dtor
0x7fff583cb3c8 ~dtor
Just MOVE it
template <typename T>
Vector<T>::Vector(Vector&& other) :
m_data(nullptr)
{
std::cout << this << " move ctor" <<
std::endl;
std::swap(m_size, other.m_size);
std::swap(m_data, other.m_data);
}
template <typename T>
Vector<T>& Vector<T>::operator= (Vector&& rhs)
{
std::cout << this << " move assignment
operator" << std::endl;
std::swap(m_size, rhs.m_size);
std::swap(m_data, rhs.m_data);
return *this;
}
Just MOVE it
Vector<int> v3(1000);
Std::cout << "== create temporary in place" <<
std::endl;
v3 = Vector<int>(2);
std::cout << "== creating temporary through return
value" << std::endl;
v3 = CreateVector<int>(1000);
yury.gavrilovich@yurys-Mac ~/ $ clang++ -std=c++11 -O0 041.cc &&
./a.out
0x7fff5e9193c8 ctor
== create temporary in place
0x7fff5e9193a8 ctor
0x7fff5e9193c8 move assignment operator
0x7fff5e9193a8 ~dtor
== creating temporary through return value
0x7fff5e919398 ctor
0x7fff5e9193c8 move assignment operator
0x7fff5e919398 ~dtor
0x7fff5e9193c8 ~dtor
Anything besides move constructors? You can
std::move() things!
But… what is std::move()?
std::move() - makes T&& from anything since 2011
Implementation:
template<class T>
typename remove_reference<T>::type&&
std::move(T&& a) noexcept
{
typedef typename remove_reference<T>::type&& RvalRef;
return static_cast<RvalRef>(a);
}
Equivalent to:
static_cast<typename std::remove_reference<T>::type&&>(t)
Example:
Vector<int> v3(1);
auto x1 = std::move(v3); // explicit intention
auto x2 = static_cast<Vector<int>&&>(x1); // ugly
std::move example 1
Vector<int> v1(1000);
Vector<int> v2 = std::move(v1); // don't
care about v1 anymore
Vector<int> v3(v1); // easy way to get
segfault
lite @ yurketPC ~/ $ g++ -std=c++11 -O0 041.cc && ./a.out
0x7ffe881fe0b0 ctor
0x7ffe881fe0c0 move ctor
0x7ffe881fe0d0 copy ctor
0x7ffe881fe0d0 copying data into allocated memory
Segmentation fault
std::move example 2a
Vector<double> v1(1000);
std::vector<Vector<double>> v;
v.push_back(v1);
lite @ yurketPC ~/ $ g++ -std=c++11 -O0 041.cc && ./a.out
0x7ffc61c22930 ctor
0xd52f80 copy ctor
0xd52f80 copying data into allocated memory
0xd52f80 ~dtor
0x7ffc61c22930 ~dtor
lite @ yurketPC ~/ $ valgrind ./a.out
==23980== HEAP SUMMARY:
==23980== in use at exit: 72,704 bytes in 1 blocks
==23980== total heap usage: 5 allocs, 4 frees, 89,744 bytes
allocated
std::move example 2b
Vector<double> v1(1000);
std::vector<Vector<double>> v;
v.push_back(std::move(v1));
lite @ yurketPC ~/ $ g++ -std=c++11 -O0 041.cc && ./a.out
0x7ffcc5fecc00 ctor
0x1ebaf80 move ctor
0x1ebaf80 ~dtor
0x7ffcc5fecc00 ~dtor
lite @ yurketPC ~/ $ valgrind ./a.out
==24060== HEAP SUMMARY:
==24060== in use at exit: 72,704 bytes in 1 blocks
==24060== total heap usage: 4 allocs, 3 frees, 81,744 bytes
allocated
Movable only
types
● Non-value types
● Only 1 instance should exist
● unique_ptr is a good example
● Poco MongoDB connections(nice “side effect”)
Movable but not copyable example
typedef std::unique_ptr<Vector<int>> VectorPtr;
std::vector<VectorPtr> v1, v2;
v1.push_back(VectorPtr(new Vector<int>(10)));
v2 = v1; // error: use of deleted function unique_ptr<T>&
unique_ptr<T>::operator=(const unique_ptr<T>&)
v2 = std::move(v1); // OK
So. Move
semantics is
good because...
● Improves performance for new
code (inplace sorting in STL
containers)
● Free performance gain by
upgrading from C++03 to C++11
● Allows movable only types
move
semantics
perfect
forwarding
briefly
lvalues vs
rvalues
rvalue
references
forwarding
references
briefly
Forwarding references (T&&)
Forwarding reference is special reference in type deduction
context (in type declaration, or template parameters) which
can be resolved to either rvalue reference or lvalue
reference
Forwarding references. Example 1
int&& rr = 13; // explicitly declared rvalue
// type deduction taking place
int i = 14;
auto&& ar = i; // ar is lvalue reference of type int&
auto&& ar2 = 15; // ar2 is rvalue reference of type int&&
Forwarding references. Example 2
template <typename T>
void foo(T&& arg)
{
...
}
int i = 13;
foo(i); // arg is of type int&
foo(5); // arg is of type int&&
Reference collapsing rule on type deduction
The rule is very simple. & always wins.
● A& & becomes A&
● A& && becomes A&
● A&& & becomes A&
● A&& && becomes A&&
Special type deduction rules
template<typename T>
void foo(T&&);
1. When foo is called on an lvalue of type A, then T resolves to A& and hence, by the
reference collapsing rules above, the argument type effectively becomes A&.
2. When foo is called on an rvalue of type A, then T resolves to A, and hence the
argument type becomes A&&.
Forwarding references. Example 2
template <typename T>
void foo(T&& arg)
{
...
}
int i = 13;
foo(i); // foo(int& && arg) -> arg is of type int&
foo(5); // foo(int && arg) -> arg is of type int&&
The main thing to remember about T&& -
Forwarding reference preserve the value category
(lvaluesness or rvaluesness) of its “argument”. Or we can
say they FORWARD value category.
move
semantics
forwarding
references
briefly
lvalues vs
rvalues
rvalue
references
perfect
forwarding
briefly
Problem is pretty old
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002
/n1385.htm
Document number: N1385=02-0043
Programming Language C++
Peter Dimov, pdimov@mmltd.net
Howard E. Hinnant, hinnant@twcny.rr.com
Dave Abrahams, dave@boost-consulting.com
September 09, 2002
The problem
We'd like to define a function
f(t1, …, tn) with generic
parameters that forwards its
parameters perfectly to some
other function E(t1, …,
tn).
The problem
pseudocode
template <typename T1, typename T2>
void f(T1? t1, T2? t2)
{
E(?t1, ?t2);
}
Homework #2: Try to derive such a
function (or set of functions) for a
number of parameter types: T, T&,
const T& in terms of C++03
The solution
template<typename T1, typename T2>
void f(T1&& t1, T2&& t2)
{
E(std::forward<T1>(t1),
std::forward<T2>(t2));
}
1) forwarding references
2) std::forward()
std::forward( )
template<class T>
T&& forward(typename std::remove_reference<T>::type& t)
noexcept {
return static_cast<T&&>(t);
}
Forwards lvalues as either lvalues or as rvalues, depending on T (much easier
to grasp this concept after Homework #1)
rvalue
references
move
semantics
forwarding
references
briefly
perfect
forwarding
briefly
What to remember?
lvalues
vs rvalues
The end
Homework ##: RVO + copy elision
Vector& operator= (Vector const& rhs)
{
std::cout << this << " copy assignment operator"
<< std::endl;
Vector<T> tmp(rhs);
swap(*this, tmp);
return *this;
}
Why do we need move ctor then?
Vector& operator= (Vector rhs)
{
std::cout << this << " copy assignment operator" <<
std::endl;
swap(*this, rhs);
return *this;
}
How more than 1 reference could be?
template <typename T>
void bar(T t) {
T& v = t; // int& & v = t;
}
int i = 13;
bar<int&>(i);

More Related Content

PDF
Introduction to c++ ppt
PPT
OOP in C++
PPT
C++ Pointers And References
PPTX
Operator overloading and type conversion in cpp
PPT
Operators in C++
PPTX
Function in c language(defination and declaration)
PPTX
Friend function & friend class
PPTX
Strings in c++
Introduction to c++ ppt
OOP in C++
C++ Pointers And References
Operator overloading and type conversion in cpp
Operators in C++
Function in c language(defination and declaration)
Friend function & friend class
Strings in c++

What's hot (20)

PPTX
Inline Functions and Default arguments
PPTX
Functions in c++
PPTX
PPT
Functions in C++
PPT
Basics of c++ Programming Language
PDF
Javascript essentials
PPT
Pointers C programming
PPTX
Functions in C
PPTX
array of object pointer in c++
PPT
FUNCTIONS IN c++ PPT
PPTX
Function C programming
PPTX
classes and objects in C++
PPT
structure and union
PDF
Object oriented programming c++
PDF
C programming notes
PPTX
Storage classes in C
PDF
Introduction to c++ ppt 1
PPTX
Function in C program
PPTX
C programming - Pointers
PPTX
Pointers in c++
Inline Functions and Default arguments
Functions in c++
Functions in C++
Basics of c++ Programming Language
Javascript essentials
Pointers C programming
Functions in C
array of object pointer in c++
FUNCTIONS IN c++ PPT
Function C programming
classes and objects in C++
structure and union
Object oriented programming c++
C programming notes
Storage classes in C
Introduction to c++ ppt 1
Function in C program
C programming - Pointers
Pointers in c++
Ad

Viewers also liked (20)

PDF
Диаграммы состояний и c++
PDF
C++ refelection and cats
PPTX
Повседневный С++: алгоритмы и итераторы
PPTX
Mixing c++ and python
PPTX
модели акторов в с++ миф или реальность
PPTX
строим Microkernel architecture на базе паттерна pipes and filters
PDF
шишки, набитые за 15 лет использования акторов в c++ v.001.3
PDF
Oxygine 2 d objects,events,debug and resources
PPTX
Современный статический анализ кода: что умеет он, чего не умели линтеры
PPTX
Unit tests final
PPTX
Mixing d ps building architecture on the cross cutting example
PDF
модель акторов и C++ что, зачем и как ?
PPTX
карта It профессий, точки входа, первые шаги
PPTX
многогранная профессия тестировщика глазами с++ разработчика в примерах
PPTX
Alternative ways of learning programming from scratch – first steps in automa...
PPTX
Python test-automation
PPTX
низкоуровневое программирование сегодня новые стандарты с++, программирован...
PPTX
Алексей Кутумов, C++ без исключений, часть 3
PPT
Advantage and Disadvantages of MULTIMEDIA
DOCX
Multimedia in education
Диаграммы состояний и c++
C++ refelection and cats
Повседневный С++: алгоритмы и итераторы
Mixing c++ and python
модели акторов в с++ миф или реальность
строим Microkernel architecture на базе паттерна pipes and filters
шишки, набитые за 15 лет использования акторов в c++ v.001.3
Oxygine 2 d objects,events,debug and resources
Современный статический анализ кода: что умеет он, чего не умели линтеры
Unit tests final
Mixing d ps building architecture on the cross cutting example
модель акторов и C++ что, зачем и как ?
карта It профессий, точки входа, первые шаги
многогранная профессия тестировщика глазами с++ разработчика в примерах
Alternative ways of learning programming from scratch – first steps in automa...
Python test-automation
низкоуровневое программирование сегодня новые стандарты с++, программирован...
Алексей Кутумов, C++ без исключений, часть 3
Advantage and Disadvantages of MULTIMEDIA
Multimedia in education
Ad

Similar to C++ references (20)

PDF
Hot C++: Rvalue References And Move Semantics
PDF
C++11: Rvalue References, Move Semantics, Perfect Forwarding
PDF
[OLD VERSION, SEE DESCRIPTION FOR NEWER VERSION LINK] Hot C++: Rvalue Referen...
PDF
C++11 talk
PDF
The C++ rvalue lifetime disaster. Arno Schödl ➠ CoreHard Autumn 2019
PPTX
Beginning direct3d gameprogrammingcpp02_20160324_jintaeks
PPTX
C++11 move semantics
PPT
What's New in C++ 11?
PPTX
Lecture 3, c++(complete reference,herbet sheidt)chapter-13
PDF
Bjarne essencegn13
PDF
C++ 11 usage experience
PPTX
Elements of C++11
PDF
(4) cpp automatic arrays_pointers_c-strings
PPT
Gentle introduction to modern C++
PDF
How to avoid bugs using modern C++
PPTX
C++11 - STL Additions
PPTX
C++11: Feel the New Language
PDF
Memory Management with Java and C++
PPTX
PDF
[OLD VERSION, SEE DESCRIPTION FOR THE NEWER VERSION LINK] Hot С++: Universal ...
Hot C++: Rvalue References And Move Semantics
C++11: Rvalue References, Move Semantics, Perfect Forwarding
[OLD VERSION, SEE DESCRIPTION FOR NEWER VERSION LINK] Hot C++: Rvalue Referen...
C++11 talk
The C++ rvalue lifetime disaster. Arno Schödl ➠ CoreHard Autumn 2019
Beginning direct3d gameprogrammingcpp02_20160324_jintaeks
C++11 move semantics
What's New in C++ 11?
Lecture 3, c++(complete reference,herbet sheidt)chapter-13
Bjarne essencegn13
C++ 11 usage experience
Elements of C++11
(4) cpp automatic arrays_pointers_c-strings
Gentle introduction to modern C++
How to avoid bugs using modern C++
C++11 - STL Additions
C++11: Feel the New Language
Memory Management with Java and C++
[OLD VERSION, SEE DESCRIPTION FOR THE NEWER VERSION LINK] Hot С++: Universal ...

More from corehard_by (20)

PPTX
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
PPTX
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
PDF
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
PPTX
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
PPTX
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
PPTX
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
PPTX
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
PPTX
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
PDF
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
PPTX
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
PPTX
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
PDF
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
PDF
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
PDF
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
PDF
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
PPTX
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
PDF
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
PDF
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019

Recently uploaded (20)

PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
MYSQL Presentation for SQL database connectivity
PPTX
Tartificialntelligence_presentation.pptx
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
cuic standard and advanced reporting.pdf
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Getting Started with Data Integration: FME Form 101
PDF
Approach and Philosophy of On baking technology
PPTX
A Presentation on Artificial Intelligence
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Encapsulation theory and applications.pdf
Spectral efficient network and resource selection model in 5G networks
MYSQL Presentation for SQL database connectivity
Tartificialntelligence_presentation.pptx
Assigned Numbers - 2025 - Bluetooth® Document
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
MIND Revenue Release Quarter 2 2025 Press Release
“AI and Expert System Decision Support & Business Intelligence Systems”
Diabetes mellitus diagnosis method based random forest with bat algorithm
Network Security Unit 5.pdf for BCA BBA.
Mobile App Security Testing_ A Comprehensive Guide.pdf
cuic standard and advanced reporting.pdf
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Getting Started with Data Integration: FME Form 101
Approach and Philosophy of On baking technology
A Presentation on Artificial Intelligence
Building Integrated photovoltaic BIPV_UPV.pdf
Advanced methodologies resolving dimensionality complications for autism neur...
Encapsulation theory and applications.pdf

C++ references

  • 2. My name is Gavrilovich Yury =)
  • 3. Objective ● Overview of “ancient” C++11 feature: rvalue references ● Leave in your memory not numerous details but high-level ideas! ● Inspire to get profound understanding by yourselves! (Homework presents)
  • 4. For those who is not aware of: ● Rvalue references (&&) ● Forwarding (universal) references ● Move semantics ● Perfect forwarding
  • 5. lvalues vs rvalues Short reminder: “what’s the difference” with examples rvalue references What is it? The purpose? move semantics Move ctors, std::move() The problem forwarding references briefly && is not only rvalue reference perfect forwarding briefly
  • 7. Formal definition from C++ standard
  • 8. Informal definition (good enough) ● If you can take the address of an expression, the expression is an lvalue ● If the type of an expression is an lvalue reference (e.g., T& or const T&, etc.), that expression is an lvalue ● Otherwise, the expression is an rvalue. (Examples: temporary objects, such as those returned from functions or created through implicit type conversions. Most literal values (e.g., 10 and 5.3))
  • 9. Homework #1 ● Function parameters (not arguments) are lvalues ● The type of an expression is independent of whether the expression is an lvalue or an rvalue. That is, given a type T, you can have lvalues of type T as well as rvalues of type T. [Effective Modern C++. Introduction]
  • 10. lvalue examples (can take address) int i = 13; // i is lvalue int* pi = &i; // can take address int& foo(); foo() = 13; // foo() is lvalue int* pf = &foo(); // can take address int i = 14; int& ri = i; // ri is lvalue int* pri = &ri; // can take address
  • 11. lvalue examples (can take address) template <typename T> T& MyVector::operator[] (std::size_t const n); MyVector<int> v{1,3,5,7}; v[0] = 2; // v[0] is lvalue int* pv = &v[0]; // can take address
  • 12. rvalue examples (can NOT take address) int i = 13; // 13 is rvalue i += 1; // 1 is rvalue yury.gavrilovich@yurys-Mac ~/$ objdump -d -x86-asm-syntax=intel a.out mov dword ptr [rbp - 8], 13 mov ecx, dword ptr [rbp - 8] add ecx, 1
  • 13. rvalue examples (can NOT take address) a + b = 3; // error: lvalue required as left operand of assignment int bar(); // bar() is rvalue bar() = 13; // error: expression is not assignable int* pf = &bar(); // error: cannot take the address of an rvalue of type 'int' struct X{}; X x = X(); // X() is rvalue X* px = &X(); // error: taking the address of a temporary object of type 'X'.
  • 14. Question for your understanding: const int i = 1; rvalue or lvalue??
  • 16. lvalue references (&) X x; X& lv = x; X& lv2 = X(); // error: non-const lvalue reference to type 'X' cannot bind to a temporary of type 'X' X const& lv3 = X(); // OK, since const&
  • 17. rvalue references (&&) X x; X&& rv2 = x; // error: rvalue reference to type 'X' cannot bind to lvalue of type 'X' X&& rv = X(); // OK
  • 18. rvalue references (&&) rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higher performance and more robust libraries. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html “A Brief Introduction to Rvalue References” Document number: N2027=06-0097 Howard E. Hinnant, Bjarne Stroustrup, Bronek Kozicki 2006-06-12
  • 19. Besides resolving aforementioned problems Rvalue references allow branching at compile time: void foo(int& a); // lvalue reference overload void foo(int&& a); // rvalue reference overload int a = 1; int bar(); foo(a); // argument is lvalue: calls foo(int&) foo(bar()); // argument is rvalue: calls foo(int&&)
  • 21. Our Vector class template <typename T> class Vector { public: explicit Vector(std::size_t const size); ~Vector(); Vector(Vector const& other); Vector& operator= (Vector const& rhs); // ... // ... private: std::size_t m_size; T* m_data; };
  • 22. Vector class. Constructor, Destructor template <typename T> Vector<T>::Vector(std::size_t const size) : m_size(size), m_data(new T[size]) { std::cout << this << " ctor" << std::endl; }; template <typename T> Vector<T>::~Vector() { std::cout << this << " ~dtor" << std::endl; delete[] m_data; }
  • 23. Vector class. Naive implementation (1-3 problems at least) template <typename T> Vector<T>::Vector(Vector const& other) : m_size(other.m_size), m_data(new T[m_size]) { std::cout << this << " copy ctor" << std::endl; std::cout << this << "t copying data into allocated memory" << std::endl; std::copy(other.m_data, other.m_data + m_size, m_data); } template <typename T> Vector<T>& Vector<T>::operator= (Vector const& rhs) { std::cout << this << " copy assignment operator" << std::endl; if (this == &rhs) { return *this; } std::cout << this << "t removing old data" << std::endl; delete[] m_data; m_size = rhs.m_size; std::cout << this << "t allocating and copying data" << std::endl; m_data = new T[rhs.m_size]; std::copy(rhs.m_data, rhs.m_data + m_size, m_data); return *this; }
  • 24. C++ exception safety levels (wikipedia) 1) No-throw guarantee, also known as failure transparency 2) Strong exception safety, also known as commit or rollback semantics 3) Basic exception safety, also known as a no-leak guarantee 4) No exception safety: No guarantees are made.
  • 25. A better implementation (copy_and_swap idiom - strong exception guarantee) template <typename T> Vector<T>::Vector(Vector const& other) : m_size(other.m_size), m_data(new T[m_size]) { std::cout << this << " copy ctor" << std::endl; std::cout << this << "t copying data into allocated memory" << std::endl; std::copy(other.m_data, other.m_data + m_size, m_data); } template <typename T> Vector<T>& Vector<T>::operator= (Vector const& rhs) { std::cout << this << " copy assignment operator" << std::endl; Vector<T> tmp(rhs); std::swap(m_size, tmp.m_size); std::swap(m_data, tmp.m_data); return *this; }
  • 26. The problem Vector<int> v1(1000); Vector<int> v2(1); v2 = v1; // Reasonable copy, since v1 is lvalue v2 = Vector<int>(2); // Unnecessary copy template<typename T> Vector<T> CreateVector(std::size_t const n); v2 = CreateVector<int>(3); // Either unnecessary copy
  • 27. Problem example Vector<int> v3(1000); std::cout << "== create temporary in place" << std::endl; v3 = Vector<int>(2); std::cout << "== creating temporary through return value" << std::endl; v3 = CreateVector<int>(1000); yury.gavrilovich@yurys-Mac ~/ $ clang++ -std=c++11 04.cc && ./a.out 0x7fff583cb3c8 ctor == create temporary in place 0x7fff583cb3a8 ctor 0x7fff583cb3c8 copy assignment operator 0x7fff583cb310 copy ctor 0x7fff583cb310 allocating and copying data 0x7fff583cb310 ~dtor 0x7fff583cb3a8 ~dtor == creating temporary through return value 0x7fff583cb398 ctor 0x7fff583cb3c8 copy assignment operator 0x7fff583cb310 copy ctor 0x7fff583cb310 allocating and copying data 0x7fff583cb310 ~dtor 0x7fff583cb398 ~dtor 0x7fff583cb3c8 ~dtor
  • 28. Just MOVE it template <typename T> Vector<T>::Vector(Vector&& other) : m_data(nullptr) { std::cout << this << " move ctor" << std::endl; std::swap(m_size, other.m_size); std::swap(m_data, other.m_data); } template <typename T> Vector<T>& Vector<T>::operator= (Vector&& rhs) { std::cout << this << " move assignment operator" << std::endl; std::swap(m_size, rhs.m_size); std::swap(m_data, rhs.m_data); return *this; }
  • 29. Just MOVE it Vector<int> v3(1000); Std::cout << "== create temporary in place" << std::endl; v3 = Vector<int>(2); std::cout << "== creating temporary through return value" << std::endl; v3 = CreateVector<int>(1000); yury.gavrilovich@yurys-Mac ~/ $ clang++ -std=c++11 -O0 041.cc && ./a.out 0x7fff5e9193c8 ctor == create temporary in place 0x7fff5e9193a8 ctor 0x7fff5e9193c8 move assignment operator 0x7fff5e9193a8 ~dtor == creating temporary through return value 0x7fff5e919398 ctor 0x7fff5e9193c8 move assignment operator 0x7fff5e919398 ~dtor 0x7fff5e9193c8 ~dtor
  • 30. Anything besides move constructors? You can std::move() things! But… what is std::move()?
  • 31. std::move() - makes T&& from anything since 2011 Implementation: template<class T> typename remove_reference<T>::type&& std::move(T&& a) noexcept { typedef typename remove_reference<T>::type&& RvalRef; return static_cast<RvalRef>(a); } Equivalent to: static_cast<typename std::remove_reference<T>::type&&>(t) Example: Vector<int> v3(1); auto x1 = std::move(v3); // explicit intention auto x2 = static_cast<Vector<int>&&>(x1); // ugly
  • 32. std::move example 1 Vector<int> v1(1000); Vector<int> v2 = std::move(v1); // don't care about v1 anymore Vector<int> v3(v1); // easy way to get segfault lite @ yurketPC ~/ $ g++ -std=c++11 -O0 041.cc && ./a.out 0x7ffe881fe0b0 ctor 0x7ffe881fe0c0 move ctor 0x7ffe881fe0d0 copy ctor 0x7ffe881fe0d0 copying data into allocated memory Segmentation fault
  • 33. std::move example 2a Vector<double> v1(1000); std::vector<Vector<double>> v; v.push_back(v1); lite @ yurketPC ~/ $ g++ -std=c++11 -O0 041.cc && ./a.out 0x7ffc61c22930 ctor 0xd52f80 copy ctor 0xd52f80 copying data into allocated memory 0xd52f80 ~dtor 0x7ffc61c22930 ~dtor lite @ yurketPC ~/ $ valgrind ./a.out ==23980== HEAP SUMMARY: ==23980== in use at exit: 72,704 bytes in 1 blocks ==23980== total heap usage: 5 allocs, 4 frees, 89,744 bytes allocated
  • 34. std::move example 2b Vector<double> v1(1000); std::vector<Vector<double>> v; v.push_back(std::move(v1)); lite @ yurketPC ~/ $ g++ -std=c++11 -O0 041.cc && ./a.out 0x7ffcc5fecc00 ctor 0x1ebaf80 move ctor 0x1ebaf80 ~dtor 0x7ffcc5fecc00 ~dtor lite @ yurketPC ~/ $ valgrind ./a.out ==24060== HEAP SUMMARY: ==24060== in use at exit: 72,704 bytes in 1 blocks ==24060== total heap usage: 4 allocs, 3 frees, 81,744 bytes allocated
  • 35. Movable only types ● Non-value types ● Only 1 instance should exist ● unique_ptr is a good example ● Poco MongoDB connections(nice “side effect”)
  • 36. Movable but not copyable example typedef std::unique_ptr<Vector<int>> VectorPtr; std::vector<VectorPtr> v1, v2; v1.push_back(VectorPtr(new Vector<int>(10))); v2 = v1; // error: use of deleted function unique_ptr<T>& unique_ptr<T>::operator=(const unique_ptr<T>&) v2 = std::move(v1); // OK
  • 37. So. Move semantics is good because... ● Improves performance for new code (inplace sorting in STL containers) ● Free performance gain by upgrading from C++03 to C++11 ● Allows movable only types
  • 39. Forwarding references (T&&) Forwarding reference is special reference in type deduction context (in type declaration, or template parameters) which can be resolved to either rvalue reference or lvalue reference
  • 40. Forwarding references. Example 1 int&& rr = 13; // explicitly declared rvalue // type deduction taking place int i = 14; auto&& ar = i; // ar is lvalue reference of type int& auto&& ar2 = 15; // ar2 is rvalue reference of type int&&
  • 41. Forwarding references. Example 2 template <typename T> void foo(T&& arg) { ... } int i = 13; foo(i); // arg is of type int& foo(5); // arg is of type int&&
  • 42. Reference collapsing rule on type deduction The rule is very simple. & always wins. ● A& & becomes A& ● A& && becomes A& ● A&& & becomes A& ● A&& && becomes A&&
  • 43. Special type deduction rules template<typename T> void foo(T&&); 1. When foo is called on an lvalue of type A, then T resolves to A& and hence, by the reference collapsing rules above, the argument type effectively becomes A&. 2. When foo is called on an rvalue of type A, then T resolves to A, and hence the argument type becomes A&&.
  • 44. Forwarding references. Example 2 template <typename T> void foo(T&& arg) { ... } int i = 13; foo(i); // foo(int& && arg) -> arg is of type int& foo(5); // foo(int && arg) -> arg is of type int&&
  • 45. The main thing to remember about T&& - Forwarding reference preserve the value category (lvaluesness or rvaluesness) of its “argument”. Or we can say they FORWARD value category.
  • 47. Problem is pretty old http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002 /n1385.htm Document number: N1385=02-0043 Programming Language C++ Peter Dimov, pdimov@mmltd.net Howard E. Hinnant, hinnant@twcny.rr.com Dave Abrahams, dave@boost-consulting.com September 09, 2002
  • 48. The problem We'd like to define a function f(t1, …, tn) with generic parameters that forwards its parameters perfectly to some other function E(t1, …, tn).
  • 49. The problem pseudocode template <typename T1, typename T2> void f(T1? t1, T2? t2) { E(?t1, ?t2); } Homework #2: Try to derive such a function (or set of functions) for a number of parameter types: T, T&, const T& in terms of C++03
  • 50. The solution template<typename T1, typename T2> void f(T1&& t1, T2&& t2) { E(std::forward<T1>(t1), std::forward<T2>(t2)); } 1) forwarding references 2) std::forward()
  • 51. std::forward( ) template<class T> T&& forward(typename std::remove_reference<T>::type& t) noexcept { return static_cast<T&&>(t); } Forwards lvalues as either lvalues or as rvalues, depending on T (much easier to grasp this concept after Homework #1)
  • 54. Homework ##: RVO + copy elision Vector& operator= (Vector const& rhs) { std::cout << this << " copy assignment operator" << std::endl; Vector<T> tmp(rhs); swap(*this, tmp); return *this; } Why do we need move ctor then? Vector& operator= (Vector rhs) { std::cout << this << " copy assignment operator" << std::endl; swap(*this, rhs); return *this; }
  • 55. How more than 1 reference could be? template <typename T> void bar(T t) { T& v = t; // int& & v = t; } int i = 13; bar<int&>(i);