Здравствуйте, lpd, Вы писали:
lpd>Модель акторов это очень хорошо. Однако она не всегда применяется, а передача объекта в другой поток встречается на каждом шагу, и тут указатели удобны.
А что у тебя за механизм передачи данных между потоками? ) Есть конечно специфические варианты прокидывания данных через систему (типа использования PostMessage в винде или что-то подобное), которые позволяют передать указатель и не позволяют объект. Но это как бы далеко не лучший способ организации межпоточного взаимодействия. Если же у тебя всё организовано по нормальному, внутри приложения, то непонятно откуда возьмётся разница в передаче между указателем и самим объектом.
_>>Дело не в разыменования указателя, а в технике работы кэща процессора. В случае обхода одного непрерывного массива данных у тебя все запрашиваемые данные будут уже в кэше, что ускорит работу в разы. А в случае использования массива указателей они практически наверняка (ну если ты там не используешь именно для этих данных какой-нибудь специальный аллокатор на пуле) будут указывать на различные непоследовательные участки памяти...
lpd>Это при условии, что контейнер, все-таки вектор, да еще и обходится последовательно, что не столь типично.
Это как раз самый базовый сценарий. Обработка массива данных. И именно на нём максимально сильно дохнут всякие там Java/C# как раз из-за их врождённой дополнительной косвенности.
_>>Вот есть у тебя некое красивое, но не идеально оптимизированное C++ приложение (встречаются копирования объектов и т.п.). Ты добавил в него поддержку семантики перемещения и получил ускорение его работы на сколько то там процентов при сохранение внешнего вида кода. Это как считается, "нужна" или нет? )
lpd>Если нужно ускорение работы на несколько процентов, то я бы использовал ассемблер.
Но код тогда явно изменится и не в лучшую сторону.
_>>Или вот скажем у тебя есть хорошо оптимизированное приложение написанное на чистых указателях, где ты страдаешь с ручным отслеживанием всего этого дела. Ты переписал это всё на современном C++, сохранив старую производительность и при этом полностью забыл про все ужасы ручных указателей. Это считается "нужна" или нет? )
lpd>Ручные указатели ужасом мне не представляются, в отличие от всего свода правил по rvalue-ссылкам.
Ужас не в том смысле что сложные (тут как раз проблем нет), а в том что при их подобном использование программист берёт на себя кучу лишней работы, которую вполне по силам исполнять компилятору.
lpd>В принципе, если кто-то действительно может быстрый и понятный(хотя бы ему) код с move-семантикаой, то это само по себе не плохо. Кому-то вот, например нравится ассемблер, и он будет писать код, который ему нравится со вставками на ассемблере. Другой добавит туда perl6, который ему нравится.
lpd>Я к тому, что главное не использовать move-семантику только потому, что она в новом стандарте, а значит, типа, must-have.
Нуу естественно нет никаких обязательных правил, просто это одно из самых лучших нововведений, причём не имеющее аналогов больше нигде в мейнстриме. Ну и кстати говоря, тебе довольно трудно будет не использовать его: достаточно передать где-нибудь временный объект (или скажем вернуть его в return) из stl (а они там практически все умеют перемещаться) и автоматически получится использование. )))
lpd>Я еще редактировал предыдущий пост недавно, и добавлял:
lpd>На мой взгляд — обычный C++ это баланс производительностью, удобством и простотой, с возможностью ручного ассемблера. А с move-семантикой теряется простота. Кроме того, вот я когда то достаточно написал программ на ассемблере, и мне с моим опытом не очевидно, как move-семантика реализована. Компилятор резервирует место на стеке, выходит из функции, а когда стек возвращается к передвинутой локальной переменной, пропускает этот кусок памяти? или как?
Это ты сейчас описал что-то похожее на RVO. Единственный способ (без указателей) решать ту проблему с return до C++11. Но есть принципиальная разница. Во-первых в отличие от семантики перемещения это просто оптимизация, так что оно не всегда работает (зависит от компиляторов, может отключаться опциями оптимизации и т.п.). Во-вторых оно подходит только для узкой категории случаев (например в моём первом примере RVO не сработает из-за первого if'a), в то время как семантика перемещения гораздо универсальнее.
Что касается работы семантики перемещения, то она тривиальная по своим принципам. И в тоже время может быть сколько угодно сложной, т.к. полностью определяется программистом в том самом конструкторе перемещения. В самом банальном случае это может выглядеть так:
struct A{
int8_t* data;
A(int size): data(new int8_t[size]) {}
A(A&& a) {data=a.data; a.data=nullptr;} //вот тут вся наша "магия"
~A() {delete data;}
};
Специально написал этот пример с явным указателем, для простоты понимания. Естественно в нормальном случае стоило бы использовать вместо него unique_ptr<int8_t> — тогда можно было бы не выписать руками деструктор. Да, кстати, а unique_ptr тоже сам по себе работает через семантику перемещения. )))