Re[3]: Правильно ли я понимаю перемещение
От: uzhas Ниоткуда  
Дата: 19.05.16 15:34
Оценка: +3
Здравствуйте, dosik, Вы писали:

D>Т.е. по прежнему дешевле передавать в функцию ссылку на уже созданный объект — тогда вместо трех выполняем только один конструктор/деструктор.


вот вы уже лихо перешли на "дешевле", хотя изначально спросили про стандартное поведение
когда вы хотите "дешевле", то стандарт тут не помощник, тут надо уже анализировать компиляторы с их оптимизациями (copy elision, (N)RVO, inlining)

тут вся соль в том, что кол-во копирований в C++11 уменьшили до нуля. кол-во вызовов конструкторов\деструкторов на практике может не играть никакой роли, т.к. действий там мало и они вообще могут быть удалены оптимизатором
передавать ссылку на уже созданный вектор может быть дешевле в случае, если вектор внутри уже саллоцировал память (сделали reserve) и функция запихивает туда столько данных, что переаллокаций не происходит

короче, возвращать по значению сейчас не зазорно. профилируйте, а потом оптимизируйте.
Re[4]: Правильно ли я понимаю перемещение
От: Videoman Россия https://hts.tv/
Дата: 19.05.16 14:13
Оценка: +2
Здравствуйте, antropolog, Вы писали:

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


V>>А разве с приведенном коде не будет тоже самое что и в C++98, т.е. копирование?


A>12.8/32 же


A>

A>When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.


Понял, спасибо. Как же все все-таки запутано в С++11, с move семантикой.
Re[5]: Правильно ли я понимаю перемещение
От: B0FEE664  
Дата: 19.05.16 16:00
Оценка: :))
Здравствуйте, dosik, Вы писали:

U>>короче, возвращать по значению сейчас не зазорно.

D>Старики могут засмеять

А вы два амперсанда вот так поставьте:

std::vector<some_type>&& need = some_func(...)

тут они и задумаются...
И каждый день — без права на ошибку...
Re[2]: Правильно ли я понимаю перемещение
От: uzhas Ниоткуда  
Дата: 19.05.16 20:55
Оценка: 10 (1)
Здравствуйте, Erop, Вы писали:

E>Чтобы move-семантика была доступна в оригинальной версии, надо писать так:


достаточно писать

return result;

Re[3]: Правильно ли я понимаю перемещение
От: antropolog  
Дата: 19.05.16 13:50
Оценка: 8 (1)
Здравствуйте, Videoman, Вы писали:

V>А разве с приведенном коде не будет тоже самое что и в C++98, т.е. копирование?


12.8/32 же

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

Re: Правильно ли я понимаю перемещение
От: uzhas Ниоткуда  
Дата: 19.05.16 13:41
Оценка: +1
Здравствуйте, dosik, Вы писали:

D>Таким образом мы избавляемся от одного конструктора и одного деструктора? Или же конструкторы и деструкторы будут вызваны оба раза, а при перемещении произойдет лишь "передача" внутренностей?


оптимизации не учитываем

C++98
1. выполняется some_func
2. создается result
3. при выходе из функции вектор копируется во временную переменную. result уничтожается (вызывается деструктор)
4. создается need, при этом вызывается конструктор копии из временной переменной. временный объект уничтожается
5. по выходу из области видимости выполняется деструктор вектора need

С++11

все то же самое, только пару изменений:
1) в пункте 3 вместо "вектор копируется" надо написать "вектор перемещается"
2) в пункте 4 вместо "конструктор копии" надо написать "конструктор перемещения"

Таким образом кол-во деструкций не изменяется, а вместо копирований срабатывают перемещения
Re: Правильно ли я понимаю перемещение
От: Constructor  
Дата: 19.05.16 15:09
Оценка: +1
Здравствуйте, dosik, Вы писали:

D>Допустим есть код:


D>
D>std::vector<some_type> some_func(...) {
D>    std::vector<some_type> result;
D>    ......
D>    //Some code to fill vector
D>    ......
D>    return result;
D>}
D>....

D>std::vector<some_type> need = some_func(...)
D>


Мне одному кажется, что оба стандарта (и С++03, и C++11) говорят, что в данном случае должна использоваться copy elision?
Re[4]: Правильно ли я понимаю перемещение
От: dosik Россия www.dosik.ru
Дата: 19.05.16 15:42
Оценка: +1
Здравствуйте, uzhas, Вы писали:

U>передавать ссылку на уже созданный вектор может быть дешевле в случае, если вектор внутри уже саллоцировал память (сделали reserve) и функция запихивает туда столько данных, что переаллокаций не происходит

Ну тут не поспоришь...

U>короче, возвращать по значению сейчас не зазорно.

Старики могут засмеять
Re[5]: Правильно ли я понимаю перемещение
От: antropolog  
Дата: 19.05.16 15:58
Оценка: -1
Здравствуйте, dosik, Вы писали:

D>От куда же двух, два объекта создаю сам (внутри и снаружи функции) еще временная переменная.


нет никакой временной переменной, данные муваются между этими двумя инстансами.
Правильно ли я понимаю перемещение
От: dosik Россия www.dosik.ru
Дата: 19.05.16 13:26
Оценка:
Допустим есть код:

std::vector<some_type> some_func(...) {
    std::vector<some_type> result;
    ......
    //Some code to fill vector
    ......
    return result;
}
....

std::vector<some_type> need = some_func(...)

Что происходило в С++98 (сейчас говорим про стандарт, а не про оптимизацию компиляторов):
1. создается (конструируется) вектор need
2. выполняется функция some_func, в которой создается (конструируется) вектор result
3. по окончанию выполнения функции происходит копирование данных из вектора result в вектор need
5. выполняется деструктор вектора result
6. по выходу из области видимости выполняется деструктор вектора need

Что происходит в C++11 (неправильное зачеркнуть, описываю в грубом своем представлении, опять же разговор про стандарт):
1. если компилятор видит, что у std::vector<some_type> есть перемещающий конструктор, то вектор need фактически не создается (конструктор не выполняется), а создается "ссылка"
2. выполняется функция some_func, в которой создается (конструируется) вектор result
3. по окончанию выполнения функции происходит копирование "ссылки" вектора result в "ссылку" вектор need (десруктор result не выполняется)
4. по выходу из области видимости выполняется деструктор вектора need (ранее result)

Таким образом мы избавляемся от одного конструктора и одного деструктора? Или же конструкторы и деструкторы будут вызваны оба раза, а при перемещении произойдет лишь "передача" внутренностей?
Re: Правильно ли я понимаю перемещение
От: antropolog  
Дата: 19.05.16 13:38
Оценка:
Здравствуйте, dosik, Вы писали:

нет, неправильно, вектор будет создан и там и там (если не рассматривать работу оптимизатора). В первом приближении код с перемещением эквивалентен следующему:

void some_func(..., OUT std::vector<some_type>& ret) {
    std::vector<some_type> result;
    ......
    //Some code to fill vector
    ......
    ret.swap(result);
}


>Или же конструкторы и деструкторы будут вызваны оба раза, а при перемещении произойдет лишь "передача" внутренностей?

вот это
Отредактировано 19.05.2016 13:40 antropolog . Предыдущая версия .
Re[2]: Правильно ли я понимаю перемещение
От: Videoman Россия https://hts.tv/
Дата: 19.05.16 13:46
Оценка:
Здравствуйте, uzhas, Вы писали:

U>С++11


U>все то же самое, только пару изменений:

U>1) в пункте 3 вместо "вектор копируется" надо написать "вектор перемещается"
U>2) в пункте 4 вместо "конструктор копии" надо написать "конструктор перемещения"

U>Таким образом кол-во деструкций не изменяется, а вместо копирований срабатывают перемещения


А разве с приведенном коде не будет тоже самое что и в C++98, т.е. копирование?
Re[2]: Правильно ли я понимаю перемещение
От: Videoman Россия https://hts.tv/
Дата: 19.05.16 15:17
Оценка:
Здравствуйте, Constructor, Вы писали:

C>Мне одному кажется, что оба стандарта (и С++03, и C++11) говорят, что в данном случае должна использоваться copy elision?


Выше я уже задавал вопрос. Вы не согласны с ответом? Почему спрашиваю — я в С++11 пока не очень ориентируюсь.
Re[2]: Правильно ли я понимаю перемещение
От: dosik Россия www.dosik.ru
Дата: 19.05.16 15:19
Оценка:
Здравствуйте, Constructor, Вы писали:

C>Мне одному кажется, что оба стандарта (и С++03, и C++11) говорят, что в данном случае должна использоваться copy elision?


Где-то тут читал, что:
std::vector<some_type> need = some_func(...)

Аналогично:
std::vector<some_type> need = std::move(some_func(...))

Т.е. при наличии у возвращаемого из функции типа не только копирующего, но перемещающего конструктора, предпочтение отдается последнему. Программист же выбирает наиболее удобочитаемый стиль написания кода.
Re[2]: Правильно ли я понимаю перемещение
От: dosik Россия www.dosik.ru
Дата: 19.05.16 15:22
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Таким образом кол-во деструкций не изменяется, а вместо копирований срабатывают перемещения


Т.е. по прежнему дешевле передавать в функцию ссылку на уже созданный объект — тогда вместо трех выполняем только один конструктор/деструктор.
Re[3]: Правильно ли я понимаю перемещение
От: antropolog  
Дата: 19.05.16 15:24
Оценка:
Здравствуйте, dosik, Вы писали:

D>Т.е. по прежнему дешевле передавать в функцию ссылку на уже созданный объект — тогда вместо трех выполняем только один конструктор/деструктор.


вместо двух
Re[4]: Правильно ли я понимаю перемещение
От: dosik Россия www.dosik.ru
Дата: 19.05.16 15:32
Оценка:
Здравствуйте, antropolog, Вы писали:

A>вместо двух


От куда же двух, два объекта создаю сам (внутри и снаружи функции) еще временная переменная.
Re[6]: Правильно ли я понимаю перемещение
От: dosik Россия www.dosik.ru
Дата: 19.05.16 16:11
Оценка:
Здравствуйте, antropolog, Вы писали:

A>нет никакой временной переменной, данные муваются между этими двумя инстансами.


А вот uzhas в начале этого ответвления писал еще и про временную. Хотелось бы уж определиться, есть ли она?
Re[7]: Правильно ли я понимаю перемещение
От: antropolog  
Дата: 19.05.16 16:33
Оценка:
Здравствуйте, dosik, Вы писали:

D>А вот uzhas в начале этого ответвления писал еще и про временную. Хотелось бы уж определиться, есть ли она?


не было, нет и не будет.
Re[7]: Правильно ли я понимаю перемещение
От: uzhas Ниоткуда  
Дата: 19.05.16 16:46
Оценка:
Здравствуйте, dosik, Вы писали:

D>А вот uzhas в начале этого ответвления писал еще и про временную. Хотелось бы уж определиться, есть ли она?


ну вот пример от gcc с отключенной оптимизацией
  Скрытый текст


здесь уничтожено три объекта типа A
всю ответственность за потери беру на себя
это поведение вполне соответствует стандарту
Re[6]: Правильно ли я понимаю перемещение
От: uzhas Ниоткуда  
Дата: 19.05.16 16:50
Оценка:
Здравствуйте, antropolog, Вы писали:

A>нет никакой временной переменной, данные муваются между этими двумя инстансами.


ТС тянется к знаниям, а вы его только сбиваете
нехорошо
Re: Правильно ли я понимаю перемещение
От: Erop Россия  
Дата: 19.05.16 19:59
Оценка:
Здравствуйте, dosik, Вы писали:


D>Таким образом мы избавляемся от одного конструктора и одного деструктора? Или же конструкторы и деструкторы будут вызваны оба раза, а при перемещении произойдет лишь "передача" внутренностей?


По стандарту 98 поведение должно быть таким:

std::vector<some_type>& some_func(void* resultBuffer, ...) {
    std::vector<some_type> result;
    ......
    //Some code to fill vector
    ......
    return *::new(resultBffer) std::vector<some_type>( result );
}
....

// выделили место под std::vector<some_type> need;
std::vector<some_type>&need = some_func(место_под_need, ...);
// с этого момента вызывающая сторона отвечает за разрушение need


и с 98 было в стандарте же можно делать ВНУТРИ ФУНКЦИИ RVO, а с 03 и NRVO
В данном случае NRVO будет означать следующее:
std::vector<some_type>& some_func(void* resultBuffer, ...) {
    std::vector<some_type>& result = *new(resultBffer) std::vector<some_type>;
    // с этого момента и до return some_func отвечает за разрушение result 
    ......
    //Some code to fill vector
    ......
    return result;  // с этого момента за разрушение result отвечает вызывающая сторона
}


RVO же, означает следующее:
std::vector<some_type>& some_func(void* resultBuffer, ...) {
    
    //тут код, который вычисляет параметры конструктора std::vector<some_type>
    ......
    return *::new(resultBffer) std::vector<some_type>( те самые параметры конструктора );
}


Для этого исходную some_func надо писать так:
std::vector<some_type> some_func(...) {
    
    //тут код, который вычисляет параметры конструктора std::vector<some_type>
    ......
    return std::vector<some_type>( те самые параметры конструктора );
}

И для такой редакции в С++11 будет доступна move-семантика. То есть эквивалентный код будет такой:
std::vector<some_type>& some_func(void* resultBuffer, ...) {
    
    //тут код, который вычисляет параметры конструктора std::vector<some_type>
    ......
    std::vector<some_type> __temporary_object__( те самые параметры конструктора );
    return *new(resultBffer) std::vector<some_type>( static_cast<std::vector<some_type>&&>( __temporary_object__ ) );
}

Правда, насколько я понимаю, RVO всё равно доступна компилятору, так как у std::vector есть доступный конструктор копии.
Но я не понимаю зачем тут move-семантика, если у возвращаемого типа есть доступный конструктор копии.
Другое дело, если мы, например, std::unique_ptr захотим вернуть...

При этом в любом случае ВЫЗЫВАЮЩИЙ код от того, что ВНУТРИ функции пишут зависеть не должен, если не включена оптимизация вызывающего кода, использующая доступ к определению тела функции в точке вызова (то, что обычно понимают под inline)
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 19.05.2016 21:05 Erop . Предыдущая версия . Еще …
Отредактировано 19.05.2016 20:05 Erop . Предыдущая версия .
Re[3]: Правильно ли я понимаю перемещение
От: Erop Россия  
Дата: 19.05.16 21:06
Оценка:
Здравствуйте, uzhas, Вы писали:

U>достаточно писать

U>

U>return result;


Да, точно, это я тупанул.
Спасибо.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Правильно ли я понимаю перемещение
От: antropolog  
Дата: 19.05.16 22:35
Оценка:
Здравствуйте, uzhas, Вы писали:

U>здесь уничтожено три объекта типа A

U>всю ответственность за потери беру на себя
U>это поведение вполне соответствует стандарту

вполне соответствует стандарту (12.8/31) и отсутствие промежуточной переменной, и данное (дефолтное) поведение вы беспардонно отключили ключом компиляции (-fno-elide-constructors). ТС тянется к знаниям, а вы его только сбиваете. Нехорошо.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.