LINUX.ORG.RU

*values

 


1

3

Сначала коротко для тех, кто произносит C++ как «Си с классами»

  • An lvalue - привязка value к функции или объекту. (Например: если E - это pointer type expression, тогда *E - это lvalue экспрешшен, забинденный на объект или функцию, куда указывает E. Другой пример: результат вызова функции, тип результата(return_type) которой lvalue reference - это lvalue.)
  • xvalue (x значит что угодно больной фантазии) биндится к объекту, обычно в конце его жизни (так что ресурсы могут поехать (move), например). xvalue - результат определенных типов экспрешшенов, в которых есть rvalue references. (Например, результат вызова функции, тип результата которой rvalue reference - это xvalue).
  • glvalue («generalized» lvalue) == lvalue | xvalue.
  • rvalue - xvalue, временный объект или подобъект, или значение, не ассоциированное с объектом.
  • prvalue («pure» rvalue) - rvalue, такое что не xvalue. (Например, результат вызова фунции, чей тип результата не reference – это prvalue)

А теперь вопрос. Что это все значит, мать его?

Какой практический смысл имеет выделение glvalue и prvalue?

Объясните в каких местах правильно и кошерно использовать rvalue references (которые ref&&)?

Олсо, поясните за поехавшую семантику (move semantics) и семантику копирования. Вот что такое поехавшая семантика, если простыми словами? А то я втыкаю в стандарт, что отдельные слова значат - вроде понятно, а как объяснить это одной фразой? Как это юзать? Вы реально юзаете копи-конструкторы?

Короче, какие есть хорошие практики на эту тему. Как это заюзать, чтобы не получилось как на картинке: http://i.imgur.com/jmBUEjr.png

★★★★☆

Стиви, мы все уже ждем шаблоноразрывающую статью о плохом и сложном C++, на реальном опыте, а ты все по стандартам бегаешь...

FINISH HIM!

dib2 ★★★★★
()
Ответ на: комментарий от dib2

я ждал этого комментария

нет, вначале надо полностью доскрести стандарт. Более того, лепить шарики из говна легко и удобно. Это не означает, что построенный таким образом дом не будет говняным.

думаешь, (воп|вб)рос уныл и его необходимо удалить?&&

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от stevejobs

нет, вопрос хорош, чтобы потеоретизировать в перерывах между написанием кода на C++ :) пущай будет

dib2 ★★★★★
()

Объясните в каких местах правильно и кошерно использовать rvalue references (которые ref&&)?

string s1, s2, s3;
s1 = "shit";
s2 = "happens";
s3 = s1 + " " + s2;

У s3 должен вызваться конструктор && дабы просто стырить буфер из временной строки (результата +), а не копировать её целиком.

А теперь вопрос. Что это все значит, мать его?

Пишу на плюсах за еду 6й год, подобными вопросами даже не задаюсь, новый стандарт использую только частично, по ночам сплю нормально.

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Кстати, поясни по хардкору, я прав, что сервер на крестах реально писать только вполовину медленнее жабы, или совсем поехал и нужно галоперидольчику вмазаться?

на самом деле там есть удобная функция move(x), которая делает все чо надо (в смысле, эту байду не надо постоянно руками набивать), которая есть что-то вот такое:

(since C++11)(until C++14)
template< class T >
typename std::remove_reference<T>::type&& move( T&& t );		
		
(since C++14)
template< class T >
constexpr typename std::remove_reference<T>::type&& move( T&& t );

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

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от stevejobs

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

Смотря о скорости чего именно ты говоришь. Но в общем случае нет, не прав. На крестах, в отличие от, можно использовать epoll/kqueue с минимальным оверхедом.

Простой HTTP-сервер вроде как даже в примеры к boost.asio был включен, но может путаю.

или совсем поехал и нужно галоперидольчику вмазаться?

Не помешает в любом случае :)

yoghurt ★★★★★
()

в каких местах правильно и кошерно использовать rvalue references (которые ref&&)?

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

Gvidon ★★★★
()
Ответ на: комментарий от yoghurt

О скорости разработки. По скорости выполнения сервера, очевидно что оно будет быстрее жабы во много раз как реактивный самолет, в этом и смысл (_единственный_ смысл, иначе бы я взял Scala/Clojure).

Простой HTTP-сервер вроде как даже в примеры к boost.asio был включен, но может путаю.

вот это было бы неплохо где-нибудь надыбать, чтобы не ходить по граблям тысячелетней давности. vromanov посоветовал сконцентрировать чакры и запилить модуль для nginx, например :-(

stevejobs ★★★★☆
() автор топика

Олсо, поясните за поехавшую семантику (move semantics) и семантику копирования. Вот что такое поехавшая семантика, если простыми словами? А то я втыкаю в стандарт, что отдельные слова значат - вроде понятно, а как объяснить это одной фразой? Как это юзать?

http://www.stroustrup.com/C 11FAQ.html#rval

Вы реально юзаете копи-конструкторы?

А теперь объясни нам при чем тут старые добрые копирующие конструкторы, которые мы, разумеется, давно юзаем?

asaw ★★★★★
()

а как объяснить это одной фразой?

Семантика копирования - ты создаёшь независимую копию объекта. Семантика переноса - ты забираешь себе внутренности объекта, оставляя его в каком-то неопределённом состоянии.

Gvidon ★★★★
()
Последнее исправление: Gvidon (всего исправлений: 1)
Ответ на: комментарий от yoghurt

Это была рекомендация?.. *растерянность*

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs

Предположим, что у тебя внутри объекта спрятан кусок памяти с каким-то содержимым. При обычном копировании ты должен выделить новый кусок памяти и скопировать туда все данные, при переносе (move) ты просто используешь ту же самую память. Забираешь себе во владение.

Gvidon ★★★★
()
Ответ на: комментарий от Gvidon

Что при этом происходит с предыдущим синонимом на память - он продолжает работать?

Чем это отличается от указателя?

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs
#include <iostream>
#include <string>
#include <vector>

int main() {
	std::string str = "hello";
	std::vector<std::string> v;
	
	std::cout << static_cast<const void*>(str.c_str()) << std::endl;
	
	v.push_back(std::move(str));
	
	std::cout << static_cast<const void*>(v[0].c_str()) << std::endl;
	std::cout << "String = " << str << std::endl;
	return 0;
}


Результат:

0x9fc9014
0x9fc9014
String = 

Т.е. в векторе лежит именно та самая строчка, которую мы создали в начале, никакого выделения новой памяти и копирования не произошло, но поменялось содержимое объекта str. В общем случае, str будет находится в каком-то неопределённом, но валидном состоянии, попытка его дальнейшего использования - ub

Gvidon ★★★★
()

Короче, какие есть хорошие практики на эту тему. Как это заюзать, чтобы не получилось как на картинке

Простой пример для чего всё это нужно в реальной жизни. Допустим, есть у нас множество тяжеловесных объектов типа потоков или элементов GUI, которые копировать нежелательно, если вообще можно. Допустим, мы их долго конструируем и хотим, чтобы объекты эти жили у нас потом в каком-нибудь стандартном контейнере типа std::vector. Так вот для того, чтобы их туда поместить без копирования, и нужна move semantics. В противном случае приходится городить огород из умных указателей типа shared_ptr или и того хуже — работать с обычными указателями.

asaw ★★★★★
()
Ответ на: комментарий от Gvidon

а, ub. скучно, но тогда все понятно.

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от asaw

Автообъекты выделяются на стеке. Есть ли с этим какая-то сложность? Максимальный размер, скорость доступа, итп?

При использовании нескольких потоков, хорошо бы иметь прерывающийся стек, верно? GCC умеет stack segmentation ("-fsplit-stack", http://gcc.gnu.org/wiki/SplitStacks ). Как это решается в clang/llvm? (хочу юзать svn-версию шланга вместо компилятора).

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs

Автообъекты выделяются на стеке. Есть ли с этим какая-то сложность? Максимальный размер, скорость доступа, итп?

Сложность есть как раз с тем, что тебя вынуждают работать с кучей, чего ты, возможно, не желаешь.

При использовании нескольких потоков, хорошо бы иметь прерывающийся стек, верно?

Не знаю, по-моему непосредственного отношения к сабжу это уже не имеет.

asaw ★★★★★
()
Ответ на: комментарий от asaw

извини если спрашиваю ересь, просто с с++ после жабы так страшно жить, что уж лучше спросить, чем не спросить =)

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs

Чаще всего (ну то есть почти всегда) нет никакой разницы со скоростью доступа к объектам, живущим на стеке, и прочими характеристиками работы с ними. Но если нужно, то можно запретить создание объектов на стеке, сделав их конструкторы и оператор копирования private (известный прием). Что касается размеров стека, связи всего этого с потоками и прочим, то это всё зависит не только от компилятора, но и от ОС. Например, clang не умеет stack segmentation, но это не обязательно значит, что та же проблема не может быть решена по-другому с clang.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от nanoolinux

Возможно. По моему опыту основные тормоза в софте происходят далеко не из-за таких тонкостей, как попадание или непопадание чего-то там в кэш :)

asaw ★★★★★
()
Ответ на: комментарий от cdshines

У меня код весь из перемножения матриц и копирования кусков памяти. Код на жаве для этого ненамного проще (или даже «совсем не проще» - учитывая дополнительный код на борьбу с GC), но при этом кресты намного быстрее и делают в точности что я скажу. От утверждения что как язык кресты - говно не отказываюсь, а вот как либа для управления памятью они очень даже.

stevejobs ★★★★☆
() автор топика

Про *values - это просто терминология стандарта. Не читая стандарт, ты вряд-ли столкнешься использованием терминов glvalue/xvalue/prvalue.

Pavval ★★★★★
()
Ответ на: комментарий от stevejobs

что не так с shared_ptr и обычными указателями?

shared_ptr - оверхед по памяти/скорости из-за счетчика. Указатели - ручное управление памятью.

Pavval ★★★★★
()
Ответ на: комментарий от cdshines

А какие костыли нынче в С++ для юникода?

C++11 шото да дал.

Pavval ★★★★★
()
Ответ на: комментарий от nanoolinux

Спасибо. Да, на тему предсказания ветвлений тоже можно построить парочку впечатляющих графиков ))

asaw ★★★★★
()
Ответ на: комментарий от cdshines

А какие костыли нынче в С++ для юникода?

Хреновые (пользовал).

anonymous
()
Ответ на: комментарий от asaw

Чаще всего (ну то есть почти всегда) нет никакой разницы со скоростью доступа к объектам, живущим на стеке

Стэк почти всегда в кэше. Куча фрагментирована. + накладные расходы на malloc/new/new[].

anonymous
()

Вы реально юзаете копи-конструкторы?

Скорее всего, ты тоже их юзаешь (если пользуешься стл и алгоритмами).

Ну и сам пишу/использую тоже.

Какой практический смысл имеет выделение glvalue и prvalue?

По всей видимости, иногда удобнее сказать «glvalue», чем каждый раз повторяться «тут может быть или lvalue или xvalue».

Вот что такое поехавшая семантика

Что такое «поехавшая семантика» я не знаю.

А вот «move семантикy» (по моему) удобно обьяснять на примере тех же строк. Которые представляют из себя размер (инт) и указатель на буфер. Без возможности перемещать приходится только копировать. То есть выделить столько же памяти, скопировать посимвольно содержимое и установить такой же размер. После этого временный обьект разрушится. При перемещение мы можем просто скопировать указатель не копируя буфер и не выделяя новую память.

Рекомендую, если ещё не смотрел C++11 FAQ от Страуструпa. Есть даже перевод на русский.

DarkEld3r ★★★★★
()
Ответ на: комментарий от stevejobs

на самом деле там есть удобная функция move(x), которая делает все чо надо (в смысле, эту байду не надо постоянно руками набивать)

На всякий случай, move далеко не всегда надо явно писать. Скажем в таком примере в этом нет смысла:

string str1 = move(get_string());
string str2 = get_string();
Так как возвращается и так временный обьект (rvalue), то и move не нужен.

DarkEld3r ★★★★★
()
Ответ на: комментарий от stevejobs

Что при этом происходит с предыдущим синонимом на память - он продолжает работать?

rvalue ссылка подразумевает, что предыдущего синонима просто нет или он уже недоступен.

KblCb ★★★★★
()
Ответ на: комментарий от KblCb

rvalue ссылка подразумевает, что предыдущего синонима просто нет или он уже недоступен.

std::move позволяет привести к && всё, что угодно, так что это не совсем верно

Gvidon ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.