Re: C++0x move semantics?
От: jazzer Россия Skype: enerjazzer
Дата: 11.09.07 01:07
Оценка: 1 (1)
Здравствуйте, crontab, Вы писали:

C>В Си++ есть такая проблема: при конструировани динамических типов (строки, вектора) может производиться динамический alloc и копирование данных. Например:


C>string s = "abc";


C>когда как в некоторых других языках, где, скажем, динамическая строка встроена в язык, копирование не производится. Я как-то давно копался в Delphi, к примеру, и обнаружил, что компилятор сам создает для строки "abc" в константном сегменте такую структуру, которая совместима со строками в динамической памяти, и поэтому во время инициализации копируется только указатель. У таких константных строк reference counter всегда -1, что защищает их от высвобождения. Ясно, что такое возможно (полагаю) только при поддержке со стороны компилятора.


C>На одном англоязычном форуме я отметил что это есть фундаментальная проблема в С++, и что она не может быть решена в страуструповском духе.


Это проблема не С++, а стандартного класса строки (и любого другого класса с семантикой владения), который единолично владеет своим буфером, что означает, что при создании все должно быть к нему скопировано. Вот этого не избежать никак (вернее, есть способы, типа разделяемого буфера и copy-on-write, но у них есть свои недостатки, например, в многопоточном окружении). Но вполне можно написать свой класс "константной строки", который не будет владеть своим содержимым (потому что им владеет компилятор) — тогда будет только копирование указателя (правда, в твоем примере ты создаешь неконстантную строку, так что это нам здесь не поможет).
Другое дело, что в С++ (здесь есть его фундаментальная проблема) ты не можешь различить, где создан твой объект — статически в неизменяемой памяти (т.е. пребудет вовеки) или на стеке (т.е. помрет, как только мы выйдем за текущие скобки). А тебе бы наверняка не хотелось, чтобы содержимое строки вдруг отправилось в мир иной.
Вернее, для строк, известных на этапе компиляции, такой способ есть — передавай везде сами эти литералы, либо объяви свою константную строку как
const char abc[] = "abc";
const std::string abc_s = "abc"; //2

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

Вообще говоря, в строке 2 умный компилятор, зная, как устроена стандатная строка, может понять, можно ли обойтись без динамической инициализации и просто сгенерить соответствующую структуру в неизменяемой памяти. В принципе, он это может сделать и сейчас, поскольку строка стандартная и семантика ее известна.

Но в C++0x дополнительно введут литералы пользовательских типов, так что можно будет писать так:
const std::string abc_s = "abc"s; // C++0x

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

C>А следовательно не будет решена никогда, и в итоге С++ будет уступать другим языкам в плане производительности. На что мне ответили, что в C++0x якобы проблема решена:

C>http://en.wikipedia.org/wiki/C++0x#Rvalue_Reference.2FMove_semantics

C>и все разошлись довольные. А я так и не понял как эти мув-конструкторы помогают избежать копирования, например, простого строкого литерала, когда он присваивается классу string.


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

Мув-копирование помогает защититься от создания временных копий объекта, например, если бы ты писал
std::string s = "abc" + another_std_string;

или если бы твой компилятор генерил неэффективный код и честно создавал все временные объекты, что в твоем случае было бы эквивалентно двум аллокациям
std::string s = std::string("abc");

но от копирования в целевой объект оно защитить никак не может, раз это копирование требуется семантикой этого объекта.

А с временными объектами это работает так: сейчас результат сложения (временный объект) должен быть скопирован во вновь создаваемый, но потом временный объект должен быть разрушен. Так как он все равно должен быть разрушен, нам, вообще говоря, все равно, что там с ним будет, потому что мы — единственные его пользователи, поэтому мы можем просто украсть его уже выделенный буфер — тогда в результате получится только обмен указателями и размерами — это и есть "мув".
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
C++0x move semantics?
От: crontab  
Дата: 10.09.07 21:09
Оценка: +1
В Си++ есть такая проблема: при конструировани динамических типов (строки, вектора) может производиться динамический alloc и копирование данных. Например:

string s = "abc";

когда как в некоторых других языках, где, скажем, динамическая строка встроена в язык, копирование не производится. Я как-то давно копался в Delphi, к примеру, и обнаружил, что компилятор сам создает для строки "abc" в константном сегменте такую структуру, которая совместима со строками в динамической памяти, и поэтому во время инициализации копируется только указатель. У таких константных строк reference counter всегда -1, что защищает их от высвобождения. Ясно, что такое возможно (полагаю) только при поддержке со стороны компилятора.

На одном англоязычном форуме я отметил что это есть фундаментальная проблема в С++, и что она не может быть решена в страуструповском духе. А следовательно не будет решена никогда, и в итоге С++ будет уступать другим языкам в плане производительности. На что мне ответили, что в C++0x якобы проблема решена:
http://en.wikipedia.org/wiki/C++0x#Rvalue_Reference.2FMove_semantics

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

Что думаете по этому поводу?
--
crontab
Re: C++0x move semantics?
От: WiseAlex Беларусь  
Дата: 11.09.07 07:12
Оценка:
Здравствуйте, crontab, Вы писали:

C>Я как-то давно копался в Delphi, к примеру, и обнаружил, что компилятор сам создает для строки "abc" в константном сегменте такую структуру, которая совместима со строками в динамической памяти, и поэтому во время инициализации копируется только указатель. У таких константных строк reference counter всегда -1, что защищает их от высвобождения. Ясно, что такое возможно (полагаю) только при поддержке со стороны компилятора.

Просто в делфи (насколько я помню) существует только один класс строк, соответственно и оптимизацию для него сделать проще — в с++ такого нет...
Основная проблема, как правильно отметил jazzer, невозможность отличить константный временный объект от постоянного
Впрочем, мне кажется, что случаи, где создание строк из литералов является узким местом не так часто встречаются.
Re: C++98 move semantics
От: remark Россия http://www.1024cores.net/
Дата: 11.09.07 12:36
Оценка:
Здравствуйте, crontab, Вы писали:

C>На что мне ответили, что в C++0x якобы проблема решена:


На всякий случай напомню, что move semantics в некотором виде реализуются и в текущем C++98.
Подробности здесь: Move Constructors


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.