Re[2]: Передача владения: вот как все на самом деле...
От: zaufi Земля  
Дата: 13.03.13 21:48
Оценка: 2 (1) +1
до мня вот дошло наконец, почему, последний пример кажется "неправильным"... а на самом деле, все так и должно быть!

http://liveworkspace.org/code/30T2cT$0
здесь пример в котором unique_ptr заменен на test -- структуру, которая спамит все операции над собой.

как видим, последний case выглядит какбудто в func3 передали ссылку на test (который лежит в стеке main'a) -- и на самом деле так оно и есть!

как известно функция std::move ничего не делает -- т.е. она вообще не занимается ни каким перемещением!
фактически она делает только вот такой вот cast: static_cast<X&&>(x) -- о чем можно почитать (здесь или здесь, ну или повтыкать исходники ) все это только лишь для того, чтобы выбрать нужную функцию в случае с перегрузкой. хороший пример демонстрирующий это есть здесь -- ниже выделенного жирным


The compiler treats a named rvalue reference as an lvalue and an unnamed rvalue reference as an rvalue.


ключем к пониманию происходящего можно выделить вот это (отсюда)

An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary (an rvalue), whereas you can not bind a (non const) lvalue reference to an rvalue.

т.е. в нашем последнем примере, тот факт, что func3 принимает rvalue еше ничего не значит -- т.е. это вовсе не означает, что в этом месте должна происходить передача владения (особенно помятуя, о том, что std::move ничего не делает!). внутри func3 с полученной ссылкой, тоже ничего такого не делается -- т.е. конструктор перемещения из параметра кудато еще не вызывается -- таким образом, в этом вызове мы всего лишь имеем ссылку на некий экземпляр test (лежащий в стеке у main)... и ничего с ним не делаем, чтобы приводило к перемещению его содержимого... ну собственно а куда?

в первом и во втором случае, std:move позволяет всего лишь выбрать нужный конструктор (ага, он называется move constcutctor) -- собственно он и делает всю работу, никак не std::move -- поэтому ожидать от третего примера что p3 сделается "невалидным" не верно! -- он никуда и не перемещался!
Re[12]: to uzhas
От: Константин Россия  
Дата: 14.03.13 16:47
Оценка: +1 :)
Здравствуйте, rg45, Вы писали:

U>>какое название ты бы предложил?


R>Я уже боюсь предлагать что-либо


Изверги, нельзя же так с людьми обращаться
Re[10]: to uzhas
От: uzhas Ниоткуда  
Дата: 14.03.13 14:38
Оценка: 18 (1)
Здравствуйте, rg45, Вы писали:

R>std::move ничего никуда не перемещает!

я не спорю с этим, возможно, плохо выразился. std::move "создает" rvaluе ref и соответствующие конструкторы типа T уже сделают перемещение
std::forward сможет сделать rvalue ref только при определенных обстоятельствах

R>Что конкретно в нем не так

слишком много копирований
Re[12]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 14:59
Оценка: 18 (1)
Здравствуйте, rg45, Вы писали:

R>>>Что конкретно в нем не так

U>>слишком много копирований
R>Так-так, это уже интересно. Опыт это подтверждает:
R>http://liveworkspace.org/code/3Mun0g$13.
R>Я, правда, пока еще не понял, откуда они берутся (с учетом того, что std::forward возвращет rvalue reference), буду разбираться, но все равно спасибо.

Нужен move assignment:

A &operator=(A&&)
...
a=std::forward<T>(b);
Re[16]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 18:10
Оценка: 18 (1)
Здравствуйте, rg45, Вы писали:

R>Ну, во-первых, то, о чем я уже говорил — несоответствующее название. Во-вторых, нечеткость семантики — по обеим функциям в стандарте говорится только о том, как они реализованы, а их семантика и область применимости остается на додумывание пользователю.


Семантика следует из определения, "20.2.3 forward/move helpers" — там даже примеры есть.

R>То, что во многих случаях эти функции взаимозаменяемы еще больше путает.


Функции используются в разных контекстах, у них разная семантика, разный синтаксис.

R>Вы скажете, есть дополнительные материалы, в которой все подробно расписано? Отлично! Объясните, пожалуйста, со ссылкой на эти материалы, почему успешно компилируются следующие примеры:


Ок, слайды с презентации Майерса, номер 28 "Reference Collapsing"

R>http://liveworkspace.org/code/1ykoSY$1


std::forward<A>(first)

выбирается
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;

T == A, return type is T&& -> (A)&& -> A&& (rvalue reference)
далее — A(A&&)

R>http://liveworkspace.org/code/OImmo$5


forwarding(std::forward<A>(first));

выбирается
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;

T == A, return type is T&& -> (A)&& -> A&& (rvalue reference),
далее
template<typename T>
void forwarding(T &&t)
{
   A(std::forward<T>(t));
}

T == A
выбирается
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;

(потому, что named rvalue reference)
T == A, return type is T&& -> (A)&& -> A&& (rvalue reference)
далее — A(A&&)
Re: std::unique_ptr. Передача владения.
От: rumia Россия  
Дата: 13.03.13 14:52
Оценка: 15 (1)
Здравствуйте, Аноним, Вы писали:

А>Какой из них более правильный?


http://liveworkspace.org/code/3Mun0g$0
отсюда видно, что при использовании семантики перемещения поведение меняется в зависимости от
содержимого функции. Поэтому я считаю, что первый вариант лучше.
Re[11]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 17:02
Оценка: 6 (1)
Здравствуйте, Константин, Вы писали:

К>Для меня std::move хороший способ задокументировать следующее:

К>- текущее состояние нам не нужно, и может быть перемещено
К>- мы отдаём себе отчёт, что объект после этого может содержать какое-то другое (но валидное) состояние
К>- те кто могут, радостно воспользуются возможностью стащить ресурс

Это я пытался показать здесь
Автор: Evgeny.Panasyuk
Дата: 14.03.13
.
Пример в котором делается std::move, но никто ресурсы "не тащит" — никак не противоречит описанным выше пунктам.

К>std::forward я пока спинным мозгом не чувствую


Он нужен для perfect forwarding. Допустим нужно принять аргументы, неважно какие, и передать их в неизменном виде в другую функцию (если было rvalue, то нужно передать rvalue (не забыв про move)). Например это фабрика, которой нужно передать аргументы в конструктор.
Здесь всё подробно.
Re[2]: std::unique_ptr. Передача владения.
От: zaufi Земля  
Дата: 13.03.13 13:51
Оценка: -1
Здравствуйте, niXman, Вы писали:

X>первый — более универсальный.

чем это? учитывая что у unique_ptr нет копирующего конструктора, первый вариант попросту не возможен!

X>второй — более тюнингованный

собственно он же и единственный. для передачи владения нужно явно делать std::move(ptr).
Re[4]: std::unique_ptr. Передача владения.
От: zaufi Земля  
Дата: 13.03.13 14:40
Оценка: +1
Здравствуйте, rg45, Вы писали:

X>>>второй — более тюнингованный

Z>>собственно он же и единственный. для передачи владения нужно явно делать std::move(ptr).

R>Первый вариант будет работать если фактическим параметром будет rvalue-выражение. Другими словами, первый вариант будет работать в тех же случаях, что и второй


ну я специально не стал заострять на этом внимание чтобы у ТС не было желания так делать, ибо можно внезапно огрести, если не до конца понимать суть происходящего

да и в целом, ценность такого кода стремительно стремится к нулю -- заводить unique_ptr только для того чтобы тутже передать владение вызываемой функции... мне одному кажется это странным/нелепым?
Re[3]: Передача владения: вот как все на самом деле...
От: rg45 СССР  
Дата: 13.03.13 22:17
Оценка: +1
Здравствуйте, zaufi, Вы писали:

Z>т.е. в нашем последнем примере, тот факт, что func3 принимает rvalue еше ничего не значит -- т.е. это вовсе не означает, что в этом месте должна происходить передача владения (особенно помятуя, о том, что std::move ничего не делает!).

Z>...

+1

И поэтому имя 'move' лично мне кажется не очень удачным для этой функции.
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: std::unique_ptr. Передача владения.
От: rg45 СССР  
Дата: 13.03.13 22:42
Оценка: -1
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, rumia, Вы писали:


R>>http://liveworkspace.org/code/3Mun0g$0

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

R>ИМХО, не криминал. Ни использование std::move, ни передача rvalue reference в функцию еще не означают, что перемещение обязано состояться. Даже одна и та же функция может вести себя по-разному в зависимости от обстоятельств. Такова уж природа rvalue references, нужно просто это воспринимать как норму. Тем более, что для тех объектов, для которых разрешены и копирование и перемещение, использование rvalue references может оказаться полезной защитой от непреднамеренного копирования. Да и перемещение тоже — оно ведь в отдельных случаях может оказаться не таким уж дешевым. Зачем же выполнять перемещение, когда это не является необходимым?


К тому же, если рассматривать более общий случай, когда для объекта разрешено и копирование и перемещение, вполне разумно будет сделать две перегрузки — одну для обычной константной ссылки и другую для rvalue-ссылки. Например, если бы вместо unique_ptr был shared_ptr, то одна перегрузка прекрасно бы реализовывалась через другую:

void foo(shared_ptr<Bar>&& p) 
{ 
  /*"Рабочая лошадка"*/ 
  // . . .
}

void foo(const shared_ptr<Bar>& p) 
{ 
  foo(shared_ptr<Bar>(p)); // Создаем временную копию умного указателя 
                           // и передаем ее по rvalue-ссылке в первую функцию
}
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: std::unique_ptr. Передача владения.
От: rg45 СССР  
Дата: 14.03.13 12:35
Оценка: -1
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, rg45, Вы писали:


R>> еще не означают


U>в этом и есть проблема : непредсказуемость поведения или по-другому: слишком много вариантов поведения

U>можно провести аналогию: передача по неконст ссылке или по значению\конст ссылке
U>[...]
U>как бы функция g не обязана изменить аргумент, однако может
U>f не может изменить и это некоторые гарантии для пользователя этой функции
U>именно поэтому предпочитаю передавать по значению или по неконстантной ссылке
U>меньше свободы — больше предсказуемости и меньше давление на мозг

U>по поводу move: мне кажется, что все же если ограничить использование move до тех случаев, когда реально надо мувить данные, то код понимать и поддерживать будет проще

U>а что до оверхедов передвигания смартпойнтеров не 1 раз, а два, то я спокоен. проседание у меня будет наверняка в других местах да и профайлер мне поможет
U>и да, std::move неудачное название, но я под него подстраиваюсь

Возможно, я ошибаюсь, но у меня такая предубежденность, что при идеальных архитектуре и дизайне move не нужен вовсе. Т.о. move — это просто костыль, частота использования которого может служить мерилом плохого дизайна.

На счет свободы и предсказуемости — снова приходим к вопросу о том, какой случай считать частным, какой общим. Я вполне допускаю, что в каких-то случаях есть резон перестраховаться и уменьшить число возможных вариантов поведения. Но я бы не торопился с обобщениями, и не стал бы утверждать, что так следует поступать всегда. Ведь рассуждая подобным образом достаточно скоро можно прийти к заключению, что передача параметров по ссылке — это зло, а языки, в которых нет ни ссылок ни указателей — единственно верный путь.
--
Справедливость выше закона. А человечность выше справедливости.
Re[6]: std::unique_ptr. Передача владения.
От: rg45 СССР  
Дата: 14.03.13 13:26
Оценка: -1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, rg45, Вы писали:


R>>Возможно, я ошибаюсь, но у меня такая предубежденность, что при идеальных архитектуре и дизайне move не нужен вовсе. Т.о. move — это просто костыль, частота использования которого может служить мерилом плохого дизайна.


EP>А как же алгоритмы, например быстрый rotate?

EP>А как же C++11 std::swap в конце концов?
EP>
EP>template <class T> void swap (T& a, T& b)
EP>{
EP>  T c(std::move(a)); a=std::move(b); b=std::move(c);
EP>}
EP>



swap можно можно реализовать при помощи std::forward:

http://liveworkspace.org/code/3Mun0g$7

#include <iostream>
#include <utility>

template <class T> 
void swap (T& a, T& b)
{
  T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);
}

int main(int argc, char **argv) 
{
   int a = 1, b = 2;
   swap(a, b);
   std::cout << a << ", " << b << std::endl;
}
--
Справедливость выше закона. А человечность выше справедливости.
Re[9]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 14:26
Оценка: -1
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, rg45, Вы писали:


R>>Я действительно не понимаю, что мешает мне в данном случае использовать std::forward вместо std::move.


U>оно просто не работает, как если бы это был std::move, потому что именно благодаря std::move можно переместить значение из c в b

U>внутри std::swap обязательно нужно использовать rvalue ref, а std::forward просто прокидывает входящий тип и для того, чтобы он правильно его прокидывал нужно принимать T&&. для функции с двумя типами T он будет давать осечки

Я тоже приведу кое-какие ссылки — на стандарт C++11:

20.2.3 forward/move helpers

template <class T> typename remove_reference<T>::type&& move(T&& t) noexcept;

Returns: static_cast<typename remove_reference<T>::type&&>(t).


std::move ничего никуда не перемещает!

И еще раз приведу, пример из моего предыдущего сообщения, а также ссылку на работающий пример:

http://liveworkspace.org/code/3Mun0g$7

template <class T> 
void swap (T& a, T& b)
{
  T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);
}


Что конкретно в нем не так, и какие осечки в нем происходят?
--
Справедливость выше закона. А человечность выше справедливости.
Re[9]: swap move forward
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 14:41
Оценка: +1
Здравствуйте, uzhas, Вы писали:

U>внутри std::swap обязательно нужно использовать rvalue ref, а std::forward просто прокидывает входящий тип и для того, чтобы он правильно его прокидывал нужно принимать T&&.


В случае rg45 нет "прокидки", и если использовать его swap с type deduction, то там будет rvref.
Но, в примере со swap, разница с обычным move хоть формальная, но есть.
Например, если не использовать type deduction (сферический пример):
#include <iostream>
#include <ostream>
#include <utility>

template<typename T,int> void type_is();

template <int i,class T> 
void swap (T& a, T& b)
{
  type_is<decltype(std::forward<T>(a)),2*i+1>();
  type_is<decltype(std::move(a)),2*i+2>();
  T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);
}

int main() 
{
   int a = 1, b = 2;
   swap<0>(a, b);
   swap<1,int&>(a, b);
   std::cout << a << ", " << b << std::endl;
}

Вывод:

Compilation finished with errors:
/tmp/cci7QIMZ.o: In function `main':
source.cpp: ( .text.startup+0x5 ) : undefined reference to `void type_is<int&&, 1>()'
source.cpp: ( .text.startup+0xa ) : undefined reference to `void type_is<int&&, 2>()'
source.cpp: ( .text.startup+0xf ) : undefined reference to `void type_is<int&, 3>()'
source.cpp: ( .text.startup+0x14 ) : undefined reference to `void type_is<int&&, 4>()'
collect2: error: ld returned 1 exit status

Re[15]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 15:15
Оценка: -1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Если сравнивать с "forward как move", то

EP>1. move всегда возвращает rvref

std::forward тоже всегда возвращает rvref:

20.2.3/2

template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;

2 Returns: static_cast<T&&>(t).


EP>2. move использует type-deduction, ему не нужно явно передавать тип


Ну это уже проблема второго порядка. Она и так-то не очень критична, кроме того может быть тривиально решена как на уровне пользователя, так и на уровне стандарта. То, что std::forward не сбивает с толку неподходящим названием, ИМХО, гораздо важнее.
--
Справедливость выше закона. А человечность выше справедливости.
Re[8]: to uzhas
От: Константин Россия  
Дата: 14.03.13 15:40
Оценка: +1
Здравствуйте, rg45, Вы писали:

EP>>>А как же C++11 std::swap в конце концов?

EP>>> T c(std::move(a)); a=std::move(b); b=std::move(c);

R>>swap можно можно реализовать при помощи std::forward:

R>> T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);

Не знаю, работоспособен ли пример с std::forward, надеюсь, что будет Лично для меня намного читабельней и понятней вариант с std::move. Вариант с std::forward вызывает дискомфорт и недоверие.
Re[17]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 16:01
Оценка: -1
Здравствуйте, uzhas, Вы писали:

R>>std::forward тоже всегда возвращает rvref:


U>по ссылкам, что я ранее уже дал можно найти следующее

U>

U>C++11, by contrast, introduces the following reference collapsing rules:
U>A& & becomes A&
U>A& && becomes A&
U>A&& & becomes A&
U>A&& && becomes A&&


Табличка, красивая, жаль только, она слабо коррелирует и со стандартом и с практикой:

http://liveworkspace.org/code/1ykoSY$1

20.2.3/2

template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;

2 Returns: static_cast<T&&>(t).

--
Справедливость выше закона. А человечность выше справедливости.
Re[20]: to uzhas
От: rg45 СССР  
Дата: 15.03.13 10:26
Оценка: +1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

R>>Для меня это просто открытие


EP>Ну так ждём-с TC++PL 4th edition


Да уж, без предварительной подготовки подобный use case вводит в состояние легкого шока:

http://ideone.com/EbsODp

#include <iostream>

template<typename T>
T foo(T&& t)
{
  return t;   
}

int main()
{
   int a = 0;
   foo(a) = 42;
   std::cout << a << std::endl; // Output: 42
}
--
Справедливость выше закона. А человечность выше справедливости.
std::unique_ptr. Передача владения.
От: Аноним  
Дата: 13.03.13 13:35
Оценка:
Все привет!

Предположим есть функции foo, которая принимает std::unique_ptr во владение. Хотелось бы услышать мнение уважаемого комьюнити по поводу того, как более верно эта функция должна выглядеть. У меня есть 2 варианта:

Вариант номер 1:

template<class T>
void foo(std::unique_ptr<T> ptr);


Вариант номер 2:

template<class T>
void foo(std::unique_ptr<T>&& ptr); /*as "rvalue reference"*/


Какой из них более правильный?
Re: std::unique_ptr. Передача владения.
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.03.13 13:38
Оценка:
первый — более универсальный.
второй — более тюнингованный
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: std::unique_ptr. Передача владения.
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.03.13 13:57
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>чем это? учитывая что у unique_ptr нет копирующего конструктора, первый вариант попросту не возможен!

упс, не обратил внимание что это unique. сорри.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: std::unique_ptr. Передача владения.
От: rg45 СССР  
Дата: 13.03.13 14:10
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Здравствуйте, niXman, Вы писали:


X>>первый — более универсальный.

Z>чем это? учитывая что у unique_ptr нет копирующего конструктора, первый вариант попросту не возможен!

X>>второй — более тюнингованный

Z>собственно он же и единственный. для передачи владения нужно явно делать std::move(ptr).

Первый вариант будет работать если фактическим параметром будет rvalue-выражение. Другими словами, первый вариант будет работать в тех же случаях, что и второй

При использовании оптимизирующего компилятора, думаю, разницы между этими двумя вариантами нет. А для неоптимизирующего, очевидно, второй вариант предпочтительней.
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: std::unique_ptr. Передача владения.
От: zaufi Земля  
Дата: 13.03.13 15:53
Оценка:
Здравствуйте, rumia, Вы писали:

R>Здравствуйте, Аноним, Вы писали:


А>>Какой из них более правильный?


R>http://liveworkspace.org/code/3Mun0g$0

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

и что показывает данный пример?? а ничего! только лишь что компиляторы нынче несколько умнее человеков...
как видно в примере, все что попадает в эти funcN вообще не используются! this участвующих объектов всегда тот, который был в main: т.е. никакой "передачи владения" в данном _тривиальном_ случае вообще не происходит. даже симуляция каких-то действий с переданным объектом (вызов foo()) не заставляет компилятор генерить бессмысленный код (вызывать move конструкторы), даже на -О0...
Re[3]: std::unique_ptr. Передача владения.
От: zaufi Земля  
Дата: 13.03.13 15:56
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Здравствуйте, rumia, Вы писали:


R>>Здравствуйте, Аноним, Вы писали:


А>>>Какой из них более правильный?


R>>http://liveworkspace.org/code/3Mun0g$0

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

Z>и что показывает данный пример?? а ничего! только лишь что компиляторы нынче несколько умнее человеков...

Z>как видно в примере, все что попадает в эти funcN вообще не используются! this участвующих объектов всегда тот, который был в main: т.е. никакой "передачи владения" в данном _тривиальном_ случае вообще не происходит. даже симуляция каких-то действий с переданным объектом (вызов foo()) не заставляет компилятор генерить бессмысленный код (вызывать move конструкторы), даже на -О0...

кстати, как можно видеть, добавления "симуляции использования" переданного объекта, придает твоему изначальному примеру "ожидаемое" поведение ("p3" таки не печатается)
Re[3]: std::unique_ptr. Передача владения.
От: zaufi Земля  
Дата: 13.03.13 16:00
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>как видно в примере, все что попадает в эти funcN вообще не используются! this участвующих объектов всегда тот, который был в main

oops, это я перегнул -- this это у экземпляра test... он "не при делах"

anyway, никакие move конструкторы не вызываются...
Re[4]: std::unique_ptr. Передача владения.
От: zaufi Земля  
Дата: 13.03.13 16:03
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Здравствуйте, zaufi, Вы писали:


Z>>как видно в примере, все что попадает в эти funcN вообще не используются! this участвующих объектов всегда тот, который был в main

Z>oops, это я перегнул -- this это у экземпляра test... он "не при делах"

Z>anyway, никакие move конструкторы не вызываются...


OOPS2 )) чорт, да и не должны ) -- это же у unique_ptr move конструкторы должны вызываться

но все равно: как только есть какое-то реальное использование передаваемого unique_ptr пример работает как полагается... "p3" таки нет на экране
Re[5]: std::unique_ptr. Передача владения.
От: rumia Россия  
Дата: 13.03.13 16:28
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>"p3" таки нет на экране


http://liveworkspace.org/code/9biAN$0
есть. Вы func1 два раза написали.
Re[2]: std::unique_ptr. Передача владения.
От: rg45 СССР  
Дата: 13.03.13 20:21
Оценка:
Здравствуйте, rumia, Вы писали:

R>http://liveworkspace.org/code/3Mun0g$0

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

ИМХО, не криминал. Ни использование std::move, ни передача rvalue reference в функцию еще не означают, что перемещение обязано состояться. Даже одна и та же функция может вести себя по-разному в зависимости от обстоятельств. Такова уж природа rvalue references, нужно просто это воспринимать как норму. Тем более, что для тех объектов, для которых разрешены и копирование и перемещение, использование rvalue references может оказаться полезной защитой от непреднамеренного копирования. Да и перемещение тоже — оно ведь в отдельных случаях может оказаться не таким уж дешевым. Зачем же выполнять перемещение, когда это не является необходимым?
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: std::unique_ptr. Передача владения.
От: uzhas Ниоткуда  
Дата: 14.03.13 11:07
Оценка:
Здравствуйте, rg45, Вы писали:

R> еще не означают


в этом и есть проблема : непредсказуемость поведения или по-другому: слишком много вариантов поведения
можно провести аналогию: передача по неконст ссылке или по значению\конст ссылке
void f(int i)
{
...
}

void g(int& x)
{
...
}

как бы функция g не обязана изменить аргумент, однако может
f не может изменить и это некоторые гарантии для пользователя этой функции
именно поэтому предпочитаю передавать по значению или по неконстантной ссылке
меньше свободы — больше предсказуемости и меньше давление на мозг

по поводу move: мне кажется, что все же если ограничить использование move до тех случаев, когда реально надо мувить данные, то код понимать и поддерживать будет проще
а что до оверхедов передвигания смартпойнтеров не 1 раз, а два, то я спокоен. проседание у меня будет наверняка в других местах да и профайлер мне поможет
и да, std::move неудачное название, но я под него подстраиваюсь
Re[5]: std::unique_ptr. Передача владения.
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 13:10
Оценка:
Здравствуйте, rg45, Вы писали:

R>Возможно, я ошибаюсь, но у меня такая предубежденность, что при идеальных архитектуре и дизайне move не нужен вовсе. Т.о. move — это просто костыль, частота использования которого может служить мерилом плохого дизайна.


А как же алгоритмы, например быстрый rotate?
А как же C++11 std::swap в конце концов?
template <class T> void swap (T& a, T& b)
{
  T c(std::move(a)); a=std::move(b); b=std::move(c);
}
Re[7]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 13:46
Оценка:
Здравствуйте, rg45, Вы писали:

EP>>А как же алгоритмы, например быстрый rotate?

EP>>А как же C++11 std::swap в конце концов?
EP>>
EP>>template <class T> void swap (T& a, T& b)
EP>>{
EP>>  T c(std::move(a)); a=std::move(b); b=std::move(c);
EP>>}
EP>>



R>swap можно можно реализовать при помощи std::forward:


R>http://liveworkspace.org/code/3Mun0g$7


R>
R>template <class T> 
R>void swap (T& a, T& b)
R>{
R>  T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);
R>}
R>



to uzhas:
---------
Я действительно не понимаю, что мешает мне в данном случае использовать std::forward вместо std::move. Я полагаю, если ты выражаешь свое несогласие в виде оценки, то, вероятно, можешь выразить его и на словах? Буду благодарен если объяснишь.
--
Справедливость выше закона. А человечность выше справедливости.
Re[7]: std::unique_ptr. Передача владения.
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 13:46
Оценка:
Здравствуйте, rg45, Вы писали:

R>>>Возможно, я ошибаюсь, но у меня такая предубежденность, что при идеальных архитектуре и дизайне move не нужен вовсе. Т.о. move — это просто костыль, частота использования которого может служить мерилом плохого дизайна.

EP>>А как же алгоритмы, например быстрый rotate?
EP>>А как же C++11 std::swap в конце концов?
R>swap можно можно реализовать при помощи std::forward:

std::forward предназначен для других целей, и очевидно что в этом случае у std::move синтаксис лучше
move можно реализовать при помощи раскидывания static_cast по всему коду — а смысл?
Я правильно тебя понимаю, что "move — это просто костыль, буду использовать что угодно, хоть forward, хоть static_cast, но только не его"?
Re[8]: std::unique_ptr. Передача владения.
От: rg45 СССР  
Дата: 14.03.13 13:59
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

R>>>>Возможно, я ошибаюсь, но у меня такая предубежденность, что при идеальных архитектуре и дизайне move не нужен вовсе. Т.о. move — это просто костыль, частота использования которого может служить мерилом плохого дизайна.

EP>>>А как же алгоритмы, например быстрый rotate?
EP>>>А как же C++11 std::swap в конце концов?
R>>swap можно можно реализовать при помощи std::forward:

EP>std::forward предназначен для других целей, и очевидно что в этом случае у std::move синтаксис лучше


Я в курсе, для чего это предназначалось. Да только кривовато это как-то получилось: функция называется move, хотя на самом деле ничего не перемещает. Я ожидал более весомой аргументации, чем "они хотели как лучше...".

EP>move можно реализовать при помощи раскидывания static_cast по всему коду — а смысл?

EP>Я правильно тебя понимаю, что "move — это просто костыль, буду использовать что угодно, хоть forward, хоть static_cast, но только не его"?

Грубо говоря, да. Хотя бы потому, что и forward, и static_cast приводят меня ровно к тому же результату (rvalue ссылка), при этом они не скрывают от меня сути происходящего за не уместным в данном случае словом 'move'.
--
Справедливость выше закона. А человечность выше справедливости.
Re[8]: to uzhas
От: uzhas Ниоткуда  
Дата: 14.03.13 14:15
Оценка:
Здравствуйте, rg45, Вы писали:

R>Я действительно не понимаю, что мешает мне в данном случае использовать std::forward вместо std::move.


оно просто не работает, как если бы это был std::move, потому что именно благодаря std::move можно переместить значение из c в b
внутри std::swap обязательно нужно использовать rvalue ref, а std::forward просто прокидывает входящий тип и для того, чтобы он правильно его прокидывал нужно принимать T&&. для функции с двумя типами T он будет давать осечки
std::move для меня на пальцах — это автоматизация swap, то есть встроенная в язык фишка для обмена двух переменных (swap) и эта фишка ортогональна качеству дизайна имхо

что такое std:;forward можно почитать здесь:
http://thbecker.net/articles/rvalue_references/section_01.html
http://stackoverflow.com/questions/3106110/what-are-move-semantics
Re[9]: std::unique_ptr. Передача владения.
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 14:18
Оценка:
Здравствуйте, rg45, Вы писали:

EP>>move можно реализовать при помощи раскидывания static_cast по всему коду — а смысл?

EP>>Я правильно тебя понимаю, что "move — это просто костыль, буду использовать что угодно, хоть forward, хоть static_cast, но только не его"?
R>Грубо говоря, да. Хотя бы потому, что и forward, и static_cast приводят меня ровно к тому же результату (rvalue ссылка), при этом они не скрывают от меня сути происходящего за не уместным в данном случае словом 'move'.

Допустим есть код:
f(std::move(obj));
// Что здесь можно сказать об obj ?

1. obj должен быть destructable
2. если это стандартный тип (либо тип придерживающийся тех же правил), то он:

Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.

Это такое же "valid but unspecified state", как и при Basic Exception Safety Guarantee.

Допустим, внутри f это:
void f(Obj &&obj)
{
    // do nothing
}

Пункты 1 и 2 выполняются и в этом случае.
Re[11]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 14:55
Оценка:
Здравствуйте, uzhas, Вы писали:

R>>Что конкретно в нем не так

U>слишком много копирований

Так-так, это уже интересно. Опыт это подтверждает:

http://liveworkspace.org/code/3Mun0g$13.

Я, правда, пока еще не понял, откуда они берутся (с учетом того, что std::forward возвращет rvalue reference), буду разбираться, но все равно спасибо.
--
Справедливость выше закона. А человечность выше справедливости.
Re[10]: swap move forward
От: uzhas Ниоткуда  
Дата: 14.03.13 14:58
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>В случае rg45 нет "прокидки", и если использовать его swap с type deduction, то там будет rvref.


точно, я был невнимателен
в этом случае мне непринципиально std::forward или std::move использовать. лишь бы перемещалось
Re[11]: swap move forward
От: uzhas Ниоткуда  
Дата: 14.03.13 15:02
Оценка:
Здравствуйте, uzhas, Вы писали:

U>в этом случае мне непринципиально std::forward или std::move использовать. лишь бы перемещалось


на самом деле они работают по-разному, нужен именно std::move
хватит меня запутывать!
Re[13]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 15:04
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

R>>>>Что конкретно в нем не так

U>>>слишком много копирований
R>>Так-так, это уже интересно. Опыт это подтверждает:
R>>http://liveworkspace.org/code/3Mun0g$13.
R>>Я, правда, пока еще не понял, откуда они берутся (с учетом того, что std::forward возвращет rvalue reference), буду разбираться, но все равно спасибо.

EP>Нужен move assignment:


EP>
EP>A &operator=(A&&)
EP>...
EP>a=std::forward<T>(b);
EP>


Да, точно! Спасибо.

Тогда заходим на второй круг (нафиг нам этот move)
--
Справедливость выше закона. А человечность выше справедливости.
Re[14]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 15:09
Оценка:
Здравствуйте, rg45, Вы писали:

R>Тогда заходим на второй круг (нафиг нам этот move)


Если сравнивать с "forward как move", то
1. move всегда возвращает rvref
2. move использует type-deduction, ему не нужно явно передавать тип
Re[11]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 15:09
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, rg45, Вы писали:


R>>std::move ничего никуда не перемещает!

U>я не спорю с этим, возможно, плохо выразился. std::move "создает" rvaluе ref и соответствующие конструкторы типа T уже сделают перемещение
U>std::forward сможет сделать rvalue ref только при определенных обстоятельствах

R>>Что конкретно в нем не так

U>слишком много копирований

Итак, продолжаем разговор. Копирований здесь нет вовсе: http://liveworkspace.org/code/4oRZSF$0.

Есть что возразить?
--
Справедливость выше закона. А человечность выше справедливости.
Re[12]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 15:18
Оценка:
R>Здравствуйте, uzhas, Вы писали:

R>>>Что конкретно в нем не так

U>>слишком много копирований

R>Итак, продолжаем разговор. Копирований здесь нет вовсе: http://liveworkspace.org/code/4oRZSF$0.

R>Есть что возразить?

Вот так даже еще интересней:

http://liveworkspace.org/code/4oRZSF$1
--
Справедливость выше закона. А человечность выше справедливости.
Re[16]: to uzhas
От: uzhas Ниоткуда  
Дата: 14.03.13 15:19
Оценка:
Здравствуйте, rg45, Вы писали:

R>std::forward тоже всегда возвращает rvref:


по ссылкам, что я ранее уже дал можно найти следующее

C++11, by contrast, introduces the following reference collapsing rules:
A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&

Re[16]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 15:21
Оценка:
Здравствуйте, rg45, Вы писали:

EP>>Если сравнивать с "forward как move", то

EP>>1. move всегда возвращает rvref

R>std::forward тоже всегда возвращает rvref:

R>

R>20.2.3/2
R>

R>template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
R>template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
R>

R>2 Returns: static_cast<T&&>(t).


Нет, не всегда:
#include <utility>

template<typename T> void type_is();

int main()
{
   int a;
   type_is<decltype(std::forward<int>(a))>();
   type_is<decltype(std::forward<int&>(a))>();
}

Compilation finished with errors:
/tmp/cceig6tw.o: In function `main':
source.cpp: (.text.startup+0x5): undefined reference to `void type_is<int&&>()'
source.cpp: (.text.startup+0xa): undefined reference to `void type_is<int&>()'
collect2: error: ld returned 1 exit status

У Майерса целый talk на эту тему: C++ and Beyond 2012: Scott Meyers &mdash; Universal References in C++11.
Re[12]: to uzhas
От: uzhas Ниоткуда  
Дата: 14.03.13 15:24
Оценка:
Здравствуйте, rg45, Вы писали:

R>Есть что возразить?


я не понимаю что ты хочешь доказать?
тебе не нравится только название std::move? или сама возможность перетаскивать объекты?
Re[12]: swap move forward
От: rg45 СССР  
Дата: 14.03.13 15:25
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, uzhas, Вы писали:


U>>в этом случае мне непринципиально std::forward или std::move использовать. лишь бы перемещалось


U>на самом деле они работают по-разному, нужен именно std::move

U>хватит меня запутывать!

Работают, возможно, они по-разному, только приводят к одному и тому же результату. Посмотри в стандарт:

std::move

template <class T> typename remove_reference<T>::type&& move(T&& t) noexcept;

Returns: static_cast<typename remove_reference<T>::type&&>(t).


std::forward:

template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;

2 Returns: static_cast<T&&>(t).

--
Справедливость выше закона. А человечность выше справедливости.
Re[17]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 15:25
Оценка:
Здравствуйте, uzhas, Вы писали:

R>>std::forward тоже всегда возвращает rvref:

U>по ссылкам, что я ранее уже дал можно найти следующее
U>

U>C++11, by contrast, introduces the following reference collapsing rules:
U>A& & becomes A&
U>A& && becomes A&
U>A&& & becomes A&
U>A&& && becomes A&&

Да именно, я запомнил эту табличку как "lvalue reference infection" (по-моему её так Stephan T. Lavavej назвал).
Re[13]: swap move forward
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 15:29
Оценка:
Здравствуйте, rg45, Вы писали:

R>Работают, возможно, они по-разному, только приводят к одному и тому же результату. Посмотри в стандарт:


R>1 Returns: static_cast<typename remove_reference<T>::type&&>(t).


R>2 Returns: static_cast<T&&>(t).


Это семантически разные результаты. Первое — всегда rvref.
Второе rvref только если is_same<T,typename remove_reference<T>::type> или is_rvalue_reference<T>.
Re[13]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 15:50
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, rg45, Вы писали:

R>>Есть что возразить?

U>я не понимаю что ты хочешь доказать?

U>тебе не нравится только название std::move? или сама возможность перетаскивать объекты?

Как мне кажется я достаточно ясно сформулировал свою мысль: http://rsdn.ru/forum/cpp/5099696.1
Автор: rg45
Дата: 14.03.13
. Я не имел намерений что-либо доказывать, я выразил сомнение, в надежде, что вы либо согласитесь со мной, либо переубедите меня. Спорить я был вынужден вовсе не потому, что я уперся рогом и не хочу сдвинуться с места, а потому, что большинство возражений, которые я услышал были сформированы на уровне подсознания и эмоций, а некоторые просто ошибочными. Я с радостью изменю свою точку зрения, как только услышу внятное объяснение.
--
Справедливость выше закона. А человечность выше справедливости.
Re[14]: to uzhas
От: uzhas Ниоткуда  
Дата: 14.03.13 15:55
Оценка:
Здравствуйте, rg45, Вы писали:

R>Как мне кажется я достаточно ясно сформулировал свою мысль: http://rsdn.ru/forum/cpp/5099696.1
Автор: rg45
Дата: 14.03.13
.

мысль плохо сформулирована и не прослеживается связь с std::forward, уточни плиз что ты пытаешься доказать своей реализацией swap<T>
и лучше не использовать выражения без четкого определения типа "идеальная архитектура" или "зло", потому что это лишь мешает тебя понять
Re[15]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 16:05
Оценка:
Здравствуйте, uzhas, Вы писали:

R>>Как мне кажется я достаточно ясно сформулировал свою мысль: http://rsdn.ru/forum/cpp/5099696.1
Автор: rg45
Дата: 14.03.13
.

U>мысль плохо сформулирована и не прослеживается связь с std::forward, уточни плиз что ты пытаешься доказать своей реализацией swap<T>
U>и лучше не использовать выражения без четкого определения типа "идеальная архитектура" или "зло", потому что это лишь мешает тебя понять

Мы два круга уже пробежали, идти на третий уже не охота.
--
Справедливость выше закона. А человечность выше справедливости.
Re[18]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 16:08
Оценка:
Здравствуйте, rg45, Вы писали:

R>Табличка, красивая, жаль только, она слабо коррелирует и со стандартом и с практикой:


Всё в порядке:
#include <utility>

struct A
{
   A() { }
   A(A&&) { }
   
   A(const A&) = delete;
   A& operator=(const A&) = delete;
};

template<typename T>
void forwarding(T &&t)
{
   A(std::forward<T>(t));
}

int main()
{
   A first;
   //forwarding(std::move(first));
   forwarding(first);
}

Compilation finished with errors:
source.cpp: In instantiation of 'void forwarding(T&&) [b]with T = A&[/b]]':
source.cpp:22:20: required from here
source.cpp:15:4: error: use of deleted function 'A::A(const A&)'
source.cpp:8:4: error: declared here

Re[9]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 16:10
Оценка:
Здравствуйте, Константин, Вы писали:

К>Здравствуйте, rg45, Вы писали:


EP>>>>А как же C++11 std::swap в конце концов?

EP>>>> T c(std::move(a)); a=std::move(b); b=std::move(c);

R>>>swap можно можно реализовать при помощи std::forward:

R>>> T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);

К>Не знаю, работоспособен ли пример с std::forward, надеюсь, что будет


Пример работоспособен, в этом топике уже достаточное количество ссылок на разные его вариации.

К>Лично для меня намного читабельней и понятней вариант с std::move. Вариант с std::forward вызывает дискомфорт и недоверие.


Это странно слышать, учитывая то, std::move не соответствует своему названию — она ничего не перемещает, и ничего кроме static_cast не делает.
--
Справедливость выше закона. А человечность выше справедливости.
Re[10]: to uzhas
От: uzhas Ниоткуда  
Дата: 14.03.13 16:26
Оценка:
Здравствуйте, rg45, Вы писали:

R>Это странно слышать, учитывая то, std::move не соответствует своему названию — она ничего не перемещает, и ничего кроме static_cast не делает.

какое название ты бы предложил?
Re[11]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 16:27
Оценка:
Здравствуйте, uzhas, Вы писали:

R>>Это странно слышать, учитывая то, std::move не соответствует своему названию — она ничего не перемещает, и ничего кроме static_cast не делает.

U>какое название ты бы предложил?

Я уже боюсь предлагать что-либо
--
Справедливость выше закона. А человечность выше справедливости.
Re[10]: to uzhas
От: Константин Россия  
Дата: 14.03.13 16:31
Оценка:
Здравствуйте, rg45, Вы писали:


К>>Лично для меня намного читабельней и понятней вариант с std::move. Вариант с std::forward вызывает дискомфорт и недоверие.

R>Это странно слышать, учитывая то, std::move не соответствует своему названию — она ничего не перемещает, и ничего кроме static_cast не делает.

Для меня std::move хороший способ задокументировать следующее:
— текущее состояние нам не нужно, и может быть перемещено
— мы отдаём себе отчёт, что объект после этого может содержать какое-то другое (но валидное) состояние
— те кто могут, радостно воспользуются возможностью стащить ресурс

std::forward я пока спинным мозгом не чувствую

Пример, когда std::move может быть полезен — атомарное изменение выходного параметра.
bool getSomeData( ..., A& out )
{
  A ret;

  //
  // construct, update A
  // ...
  // may throw, or return false
  //

  // out is updated in atomic manner, if everything else is ok
  // c++03 analog is out.swap(ret); if there is A::swap(...)

  out = std::move(ret);
  return true;
}
Re[12]: to uzhas
От: uzhas Ниоткуда  
Дата: 14.03.13 16:33
Оценка:
Здравствуйте, rg45, Вы писали:

R>Я уже боюсь предлагать что-либо

std::move ничего не перемещает, однако если вдуматься, то связь с перемещением все же есть: функция подготавливает объект к перемещению, делает так, чтобы компилятор начал эту операцию
а если еще и использовать rvalue ref именно для перемещения (не опционального, о чем я выше писал), то и две операции сольются вместе : подготовка к перемещению и само перемещение
Re[13]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 16:47
Оценка:
Здравствуйте, uzhas, Вы писали:

U>std::move ничего не перемещает, однако если вдуматься, то связь с перемещением все же есть: функция подготавливает объект к перемещению, делает так, чтобы компилятор начал эту операцию

U>а если еще и использовать rvalue ref именно для перемещения (не опционального, о чем я выше писал), то и две операции сольются вместе : подготовка к перемещению и само перемещение

В таком случае более подходящим названием было бы prepare_to_move или как-то так. Но как по мне, весь этот "ансамбль" move/forward выглядит криво, и не плохо было бы, если бы его полностью пересмотрели.
--
Справедливость выше закона. А человечность выше справедливости.
Re[14]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 17:08
Оценка:
Здравствуйте, rg45, Вы писали:

R>Но как по мне, весь этот "ансамбль" move/forward выглядит криво, и не плохо было бы, если бы его полностью пересмотрели.


Что именно "криво"? Какие конкретно места не нравятся?
Re[19]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 17:41
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, rg45, Вы писали:


R>>Табличка, красивая, жаль только, она слабо коррелирует и со стандартом и с практикой:


EP>Всё в порядке:

EP>
  Скрытый текст
EP>#include <utility>

EP>struct A
EP>{
EP>   A() { }
EP>   A(A&&) { }
   
EP>   A(const A&) = delete;
EP>   A& operator=(const A&) = delete;
EP>};

EP>template<typename T>
EP>void forwarding(T &&t)
EP>{
EP>   A(std::forward<T>(t));
EP>}

EP>int main()
EP>{
EP>   A first;
EP>   //forwarding(std::move(first));
EP>   forwarding(first);
EP>}
EP>

EP>

EP>Compilation finished with errors:
EP>source.cpp: In instantiation of 'void forwarding(T&&) [b]with T = A&[/b]]':
EP>source.cpp:22:20: required from here
EP>source.cpp:15:4: error: use of deleted function 'A::A(const A&)'
EP>source.cpp:8:4: error: declared here



http://liveworkspace.org/code/OImmo$5

Ну где ж в порядке-то?
--
Справедливость выше закона. А человечность выше справедливости.
Re[15]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 17:44
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

R>>Но как по мне, весь этот "ансамбль" move/forward выглядит криво, и не плохо было бы, если бы его полностью пересмотрели.


EP>Что именно "криво"? Какие конкретно места не нравятся?


Ну, во-первых, то, о чем я уже говорил — несоответствующее название. Во-вторых, нечеткость семантики — по обеим функциям в стандарте говорится только о том, как они реализованы, а их семантика и область применимости остается на додумывание пользователю. То, что во многих случаях эти функции взаимозаменяемы еще больше путает. Вы скажете, есть дополнительные материалы, в которой все подробно расписано? Отлично! Объясните, пожалуйста, со ссылкой на эти материалы, почему успешно компилируются следующие примеры:

  1. http://liveworkspace.org/code/1ykoSY$1
  2. http://liveworkspace.org/code/OImmo$5
--
Справедливость выше закона. А человечность выше справедливости.
Re[20]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 17:47
Оценка:
Здравствуйте, rg45, Вы писали:

R>>>Табличка, красивая, жаль только, она слабо коррелирует и со стандартом и с практикой:

EP>>Всё в порядке:
EP>>
  Скрытый текст
EP>>#include <utility>

EP>>struct A
EP>>{
EP>>   A() { }
EP>>   A(A&&) { }
   
EP>>   A(const A&) = delete;
EP>>   A& operator=(const A&) = delete;
EP>>};

EP>>template<typename T>
EP>>void forwarding(T &&t)
EP>>{
EP>>   A(std::forward<T>(t));
EP>>}

EP>>int main()
EP>>{
EP>>   A first;
EP>>   //forwarding(std::move(first));
EP>>   forwarding(first);
EP>>}
EP>>

EP>>

EP>>Compilation finished with errors:
EP>>source.cpp: In instantiation of 'void forwarding(T&&) [b]with T = A&[/b]]':
EP>>source.cpp:22:20: required from here
EP>>source.cpp:15:4: error: use of deleted function 'A::A(const A&)'
EP>>source.cpp:8:4: error: declared here



R>http://liveworkspace.org/code/OImmo$5

R>Ну где ж в порядке-то?

Я выше показал(обрати внимание, на какой строчке "use of deleted function"), что forward не всегда возвращает rvref — табличка работает.
Если ты считаешь, что какой-то из пунктов таблички не работает — покажи пример, с указанием того, что именно ты считаешь не работает.
Re[17]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 18:51
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:
...

Теперь я вижу, что не разобрался в вопросе, буду разбираться. Спасибо за объяснение и ссылки.
--
Справедливость выше закона. А человечность выше справедливости.
Re[17]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 18:59
Оценка:
Чтобы увидеть reference collapsing в действии, нужно рассмотреть пример где std::forward возвращает lvalue reference:

forwarding(first);

->
template<typename T>
void forwarding(T &&t)
{
   A(std::forward<T>(t));
}

T == A&. Это правило есть на 26 слайде Майерса(что также видно из ошибки "source.cpp: In instantiation of 'void forwarding(T&&) [ with T = A& ]'"):
void forwarding((A&) &&t)
{
   A(std::forward<(A&)>(t));
}

Reference Collapsing ->
void forwarding(A &t)
{
   A(std::forward<A&>(t));
}

Выбирается
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;

T == A& ->
(A&)&& forward(typename remove_reference<(A&)>::type& t) noexcept;

Reference Collapsing и применение remove_reference ->
A& forward(A& t) noexcept;

return type is A&
Re[18]: to uzhas
От: rg45 СССР  
Дата: 14.03.13 19:16
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Чтобы увидеть reference collapsing в действии, нужно рассмотреть пример где std::forward возвращает lvalue reference:


Да, теперь все стало понятно. В стандарте хоть и не используется термин "universal reference", тем не менее он здесь описан достаточно ясно:

8.3.2/6
If a typedef (7.1.3), a type template-parameter (14.3.1), or a decltype-specifier (7.1.6.2) denotes a type TR
that is a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type
“lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR.
[ Example:

int i;
typedef int& LRI;
typedef int&& RRI;
LRI& r1 = i; // r1 has the type int&
const LRI& r2 = i; // r2 has the type int&
const LRI&& r3 = i; // r3 has the type int&
RRI& r4 = i; // r4 has the type int&
RRI&& r5 = 5; // r5 has the type int&&
decltype(r2)& r6 = i; // r6 has the type int&
decltype(r2)&& r7 = i; // r7 has the type int&

—end example ]

Для меня это просто открытие
--
Справедливость выше закона. А человечность выше справедливости.
Re[19]: to uzhas
От: Evgeny.Panasyuk Россия  
Дата: 14.03.13 19:32
Оценка:
Здравствуйте, rg45, Вы писали:

R>Да, теперь все стало понятно. В стандарте хоть и не используется термин "universal reference", тем не менее он здесь описан достаточно ясно:

R>

R>8.3.2/6


Это скорее просто Reference Collapsing Rules example.
То, что Майерс называет "universal reference", относится к && в контексте type deduction, например:
auto &&v = ...;
or
template<typename T>
void f(T &&v);

То есть для "universal reference" наличие type deduction — обязательно.

R>Для меня это просто открытие


Ну так ждём-с TC++PL 4th edition
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.