Подсчет ссылок в реализации std::string
От: Шахтер Интернет  
Дата: 22.07.04 01:15
Оценка:
Здравствуйте, ArtDenis, Вы писали:

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


F>> Есть некий класс, в котором отсутствует конструктор без параметров.

F>> Интересные места выделены жирным: [ccode]

AD>У... Как всё у нас тут запущено...


AD>Сейчас кое-кто забросает меня тухлыми яйцами, но если сделать вот так:


AD>
AD>class CTask
AD>{
AD>  int id;
AD>  std::vector<char> message;

AD>public:
AD>  ...
AD>

AD>то можно избавиться от конструктора копирования, оператора присваивания, оператора new и геммороя с освобождением памяти. И код будет в четыре раза короче.

AD>ЗЫ: сижу в резиновом плаще и жду


Дождался. Большого и тухлого.

class CTask
{
  int id;
  std::string message;
    
public:
  ...


Опрация копирования для векторов неэффективна. Надо использовать std::string.
... << RSDN@Home 1.1.0 stable >>

25.07.04 09:24: Ветка выделена из темы "Поднимите мне веки" и контейнеры STL
Автор: Flamer
Дата: 20.07.04
— Павел Кузнецов
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: Подсчет ссылок в реализации std:
От: ArtDenis Россия  
Дата: 22.07.04 04:06
Оценка: +1
Здравствуйте, Шахтер, Вы писали:

Ш> Дождался. Большого и тухлого.

Ш>
 Ш> class CTask
 Ш> {
 Ш>   int id;
 Ш>   std::string message;

 Ш> public:
 Ш>   ...
 Ш>

Ш> Опрация копирования для векторов неэффективна. Надо использовать std::string.

Не все реализации std::string основаны на подсчёте ссылок. Для обычных std::string операция копировния по скорости аналогична std::vector<char>.

Кроме того, для std::vector<char> мы гарантированно имеем неразрывную последовательность данных в памяти (иногда это бывает очень важно).
Posted via RSDN NNTP Server 1.9 beta
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: Подсчет ссылок в реализации std:
От: MaximE Великобритания  
Дата: 22.07.04 09:24
Оценка:
Шахтер wrote:

> Опрация копирования для векторов неэффективна. Надо использовать std::string.


Копирование у строк эффективние? Хотелось бы узнать подробности.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 beta
Re[4]: Подсчет ссылок в реализации std:
От: Шахтер Интернет  
Дата: 22.07.04 18:52
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Шахтер wrote:


>> Опрация копирования для векторов неэффективна. Надо использовать std::string.


ME>Копирование у строк эффективние? Хотелось бы узнать подробности.


ME>--

ME>Maxim Yegorushkin

При копировании вектора создаётся копия данных. При копировании строк накручивается счётчик ссылок.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: Подсчет ссылок в реализации std:
От: Шахтер Интернет  
Дата: 22.07.04 18:52
Оценка: -1
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, Шахтер, Вы писали:


Ш>> Дождался. Большого и тухлого.

Ш>>
 Ш>> class CTask
 Ш>> {
 Ш>>   int id;
 Ш>>   std::string message;

 Ш>> public:
 Ш>>   ...
 Ш>>

Ш>> Опрация копирования для векторов неэффективна. Надо использовать std::string.

AD>Не все реализации std::string основаны на подсчёте ссылок. Для обычных std::string операция копировния по скорости аналогична std::vector<char>.


Это каких, обычных? Если реализация string клонирует строку при копировании, это значит -- кривая реализация.

AD>Кроме того, для std::vector<char> мы гарантированно имеем неразрывную последовательность данных в памяти (иногда это бывает очень важно).


При работе со строками, обычно это неважно.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Подсчет ссылок в реализации std:
От: c-smile Канада http://terrainformatica.com
Дата: 22.07.04 18:57
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>При копировании вектора создаётся копия данных. При копировании строк накручивается счётчик ссылок.


Это ты про std::string ?
Re[6]: Подсчет ссылок в реализации std:
От: Шахтер Интернет  
Дата: 22.07.04 20:22
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Здравствуйте, Шахтер, Вы писали:


Ш>>При копировании вектора создаётся копия данных. При копировании строк накручивается счётчик ссылок.


CS>Это ты про std::string ?


Ну почему. Про любую вменяемую реализацию строк.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[7]: Подсчет ссылок в реализации std:
От: adontz Грузия http://adontz.wordpress.com/
Дата: 22.07.04 20:33
Оценка:
Здравствуйте, Шахтер, Вы писали:

CS>>Это ты про std::string ?

Ш>Ну почему. Про любую вменяемую реализацию строк.

странные ты вещи говоришь. По твоим словам выходит так.

1  std::string a;
2  std::string b;
3  a = "aaaa";
4  b = a;
5  a = "bbbb";


Либо после выполнения пятой строки значение b так же равно "bbbb", либо при выполнении пятой строки создаётся копия строки a (copy on write), а для этого строка a должна умето получать список всех своих копий.
И то и другое мало похоже на правду
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[8]: Подсчет ссылок в реализации std:
От: Flamer Кипр http://users.livejournal.com/_flamer_/
Дата: 22.07.04 20:50
Оценка: +1 :)
Здравствуйте, adontz, Вы писали:

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


CS>>>Это ты про std::string ?

Ш>>Ну почему. Про любую вменяемую реализацию строк.

A>странные ты вещи говоришь. По твоим словам выходит так.


A>
A>1  std::string a;
A>2  std::string b;
A>3  a = "aaaa";
A>4  b = a;
A>5  a = "bbbb";
A>


A>Либо после выполнения пятой строки значение b так же равно "bbbb", либо при выполнении пятой строки создаётся копия строки a (copy on write), а для этого строка a должна умето получать список всех своих копий.

A>И то и другое мало похоже на правду

Чего-то я (наверное по недомыслию) не нахожу неоднозначностей в твоем примере... Как вариант моей трактовки:

1  std::string a;
2  std::string b;
3  a = "aaaa"; // reference count to "aaaa" = 1 (self)
4  b = a;      // reference count to "aaaa" = 2 (a and b). Reference count to "aaaa" in b instance = 1;
5  a = "bbbb"; // a now owned another string ("bbbb"). 
               // Decrement reference count to "aaaa" (if 0 - delete "aaaa"), 
               // then allocate new buffer for string, copy string to buffer and set 
               // reference count to 1 (exclusive ownership).
               // In this sample, b had continue ownership to string "aaaa" with reference count = 1.


Сорри фор инглиш — пиво было хорошее, и, как следствие закона сохранения энергии — инглиш получился фиговым
Re[8]: Подсчет ссылок в реализации std:
От: Шахтер Интернет  
Дата: 22.07.04 23:26
Оценка: +1
Здравствуйте, adontz, Вы писали:

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


CS>>>Это ты про std::string ?

Ш>>Ну почему. Про любую вменяемую реализацию строк.

A>странные ты вещи говоришь. По твоим словам выходит так.


A>
A>1  std::string a;
A>2  std::string b;
A>3  a = "aaaa";
A>4  b = a;
A>5  a = "bbbb";
A>


A>Либо после выполнения пятой строки значение b так же равно "bbbb", либо при выполнении пятой строки создаётся копия строки a (copy on write), а для этого строка a должна умето получать список всех своих копий.

A>И то и другое мало похоже на правду

Не буду читать сейчас лекции про строки -- у меня сегодня первый день отпуска. Просто замечание.
Хорошая реализация строкового класса должна иметь дешёвую реализацию операции копирования, которая должна быть не только O(1) по сложности, а я бы сказал даже O(0), но и не должна порождать исключений. Представь себе оператор сложения строк. В нем есть возврат строки. Если ты копируешь строки клонированием, то ты автоматически удваиваешь сложность операции сложения. В ряде случаев компилятор может тут соптимизировать, но не во всех (зависит от контекста, от качества оптимизатора, от опций, от фаз Луны, наконец). Для строк операция копировани -- естественная и часто используемая. Поэтому должна быть дешёвой. А иначе такой строковый класс нафик не нужен.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[9]: Подсчет ссылок в реализации std:
От: adontz Грузия http://adontz.wordpress.com/
Дата: 23.07.04 00:11
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Не буду читать сейчас лекции про строки -- у меня сегодня первый день отпуска. Просто замечание.


Поздравляю. с отпуском.

Ш>Хорошая реализация строкового класса должна иметь дешёвую реализацию операции копирования, которая должна быть не только O(1) по сложности, а я бы сказал даже O(0), но и не должна порождать исключений. Представь себе оператор сложения строк. В нем есть возврат строки. Если ты копируешь строки клонированием, то ты автоматически удваиваешь сложность операции сложения. В ряде случаев компилятор может тут соптимизировать, но не во всех (зависит от контекста, от качества оптимизатора, от опций, от фаз Луны, наконец). Для строк операция копировани -- естественная и часто используемая. Поэтому должна быть дешёвой. А иначе такой строковый класс нафик не нужен.


Ээээ. Ты тёплое с мягким не путай.

Первое.

Если нет RVO и проч. оптимизаций то запись
c = a + b;
должна работать так.
1) создаёться временный объект в который записывается строка a+b
2) вызывается c.operator=(временный объект).
Ты хочешь оптимизировать за счёт пункта 2. Решение правильное, но только это не копирование, а перемещение. (не COPY, а MOVE). Для реализации этой идеи никакого подсчёта ссылок не нужно. Подробнее тут http://www.cuj.com/documents/s=8246/cujcexp2102alexandr/alexandr.htm

Второе.

Предлагая использовать std::string вместо std::vector<char> ты указывал, что копирование в std::string сделано намного эффективнее. На самом деле это не так. Во всяком случае во всех известных мне реализациях.
Максимум это то, что копирование скорее всего сделано не в цикле по элементам, а с помошью memmove. Но в любом случае никакого подсчёта ссылок там нет. Так что ты жестоко ошибался.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[9]: Подсчет ссылок в реализации std:
От: adontz Грузия http://adontz.wordpress.com/
Дата: 23.07.04 00:23
Оценка:
Здравствуйте, Flamer, Вы писали:

F>Чего-то я (наверное по недомыслию) не нахожу неоднозначностей в твоем примере... Как вариант моей трактовки:


А кто сказал, что етсь неоднозначности?

F>
F>1  std::string a;
F>2  std::string b;
F>3  a = "aaaa"; // reference count to "aaaa" = 1 (self)
F>4  b = a;      // reference count to "aaaa" = 2 (a and b). Reference count to "aaaa" in b instance = 1;
F>5  a = "bbbb"; // a now owned another string ("bbbb"). 
F>               // Decrement reference count to "aaaa" (if 0 - delete "aaaa"), 
F>               // then allocate new buffer for string, copy string to buffer and set 
F>               // reference count to 1 (exclusive ownership).
F>               // In this sample, b had continue ownership to string "aaaa" with reference count = 1.
F>


Это и есть по сути copy in write. При попытке изменить исходную строку она как бы отделяется от своей копии и живёт отдельной жизнью.

Ничего невозможного в этом нет, кроме того, что это невозможно увидеть в STL Ведь мы обсуждаем не абстракный идеальный класс строки, а std::string и его преимущества перед std::vectro<char> в плане копирования.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[9]: Подсчет ссылок в реализации std:
От: folk Россия  
Дата: 23.07.04 00:37
Оценка: +1
Здравствуйте, Flamer, Вы писали:

[]

F>Чего-то я (наверное по недомыслию) не нахожу неоднозначностей в твоем примере... Как вариант моей трактовки:


F>
F>1  std::string a;
F>2  std::string b;
F>3  a = "aaaa"; // reference count to "aaaa" = 1 (self)
F>4  b = a;      // reference count to "aaaa" = 2 (a and b). Reference count to "aaaa" in b instance = 1;
F>5  a = "bbbb"; // a now owned another string ("bbbb"). 
F>               // Decrement reference count to "aaaa" (if 0 - delete "aaaa"), 
F>               // then allocate new buffer for string, copy string to buffer and set 
F>               // reference count to 1 (exclusive ownership).
F>               // In this sample, b had continue ownership to string "aaaa" with reference count = 1.
F>


С copy on write не все так хорошо как кажется. Например:
string a = "aaaa";
string b = a;
cout << a[1] << '\n'; // (*)

Оператор [] для неконстантной строки должен вернуть std::allocator<char>::reference, т.е. char&. Поскольку нельзя допускать, чтобы shared buffer был изменен через эту ссылку, то в строчке (*) должна быть создана копия исходной строки.
Вот такой уродский интерфейс у std::string

F>Сорри фор инглиш — пиво было хорошее, и, как следствие закона сохранения энергии — инглиш получился фиговым
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[10]: Подсчет ссылок в реализации std
От: adontz Грузия http://adontz.wordpress.com/
Дата: 23.07.04 00:48
Оценка:
Здравствуйте, folk, Вы писали:

F>Вот такой уродский интерфейс у std::string


Что-то я не понял. Я специально поглядел свой STL. Этот ужас что, правда где-то есть?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[10]: Подсчет ссылок в реализации std
От: Шахтер Интернет  
Дата: 23.07.04 00:56
Оценка:
Здравствуйте, adontz, Вы писали:

A>Если нет RVO и проч. оптимизаций то запись

A>c = a + b;
A>должна работать так.

Кому должна? Ты указывал на известные тебе реализации, ну так как обстоит дело в них?

A>1) создаёться временный объект в который записывается строка a+b

A>2) вызывается c.operator=(временный объект).
A>Ты хочешь оптимизировать за счёт пункта 2. Решение правильное, но только это не копирование, а перемещение. (не COPY, а MOVE). Для реализации этой идеи никакого подсчёта ссылок не нужно. Подробнее тут http://www.cuj.com/documents/s=8246/cujcexp2102alexandr/alexandr.htm

MOJO -- трюкачество.

Всё это напоминает один анекдот. Русские сделали крутой-прекрутой вездеход. Привезли его в Японию на выставку. Японцы на него посмотрели и сказали -- даа, класный вездеход. И чего эти русские только не придумают, лишь бы дороги не ремонтировать.

A>Второе.


A>Предлагая использовать std::string вместо std::vector<char> ты указывал, что копирование в std::string сделано намного эффективнее.


Нет, я писал, что в приличной реализации должно быть более эффективной. Но даже если это не так, то ты ничего не теряешь по сравнению с вектором. И есть шанс выиграть. Так что смысл использовать для хранение строк string вместо vector всё равно есть.

A>На самом деле это не так. Во всяком случае во всех известных мне реализациях.


Я видел реализации с подсчетом ссылок. Давно правда это было.

A>Максимум это то, что копирование скорее всего сделано не в цикле по элементам, а с помошью memmove. Но в любом случае никакого подсчёта ссылок там нет. Так что ты жестоко ошибался.


Повторю ещё раз. Я НЕ пользуюсь stl. Одна из причин, что не никаких гарантий, как реализован там тот или иной класс.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[10]: Подсчет ссылок в реализации std
От: Шахтер Интернет  
Дата: 23.07.04 01:26
Оценка:
Здравствуйте, folk, Вы писали:

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


F>[]


F>>Чего-то я (наверное по недомыслию) не нахожу неоднозначностей в твоем примере... Как вариант моей трактовки:


F>>
F>>1  std::string a;
F>>2  std::string b;
F>>3  a = "aaaa"; // reference count to "aaaa" = 1 (self)
F>>4  b = a;      // reference count to "aaaa" = 2 (a and b). Reference count to "aaaa" in b instance = 1;
F>>5  a = "bbbb"; // a now owned another string ("bbbb"). 
F>>               // Decrement reference count to "aaaa" (if 0 - delete "aaaa"), 
F>>               // then allocate new buffer for string, copy string to buffer and set 
F>>               // reference count to 1 (exclusive ownership).
F>>               // In this sample, b had continue ownership to string "aaaa" with reference count = 1.
F>>


F>С copy on write не все так хорошо как кажется. Например:

F>
F>string a = "aaaa";
F>string b = a;
F>cout << a[1] << '\n'; // (*)
F>

F>Оператор [] для неконстантной строки должен вернуть std::allocator<char>::reference, т.е. char&. Поскольку нельзя допускать, чтобы shared buffer был изменен через эту ссылку, то в строчке (*) должна быть создана копия исходной строки.

Да, но без COW копии будут создаваться всегда. Т.е. экономия всё равно есть, пусть и не 100%. А вообще -- не пользуйтесь stl!
Мне кажется, что немутирующие строки с подсчетом ссылок для приложений полезнее.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[11]: Подсчет ссылок в реализации std
От: folk Россия  
Дата: 23.07.04 02:31
Оценка:
Здравствуйте, adontz, Вы писали:

F>>Вот такой уродский интерфейс у std::string


A>Что-то я не понял. Я специально поглядел свой STL. Этот ужас что, правда где-то есть?


Я о таких реализациях ничего не знаю (честно говоря работал только с Dinkumware и STLport). Говорил чисто теоретически, ведь если делать string с COW, то придется как-нибудь разруливать подобные проблемы.
Еще будет чревато передавать shared-строку в другой поток. Не помню кто, кажется Саттер или Мейерс рассматривали COW применительно к строкам.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[11]: Подсчет ссылок в реализации std
От: folk Россия  
Дата: 23.07.04 02:39
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Да, но без COW копии будут создаваться всегда. Т.е. экономия всё равно есть, пусть и не 100%.


С COW усложнится релизация.

Ш>А вообще -- не пользуйтесь stl!


Как так? Пользоваться самодельными контейнерами/алгоритмами? Ты зовешь нас в каменный век!

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


Это да. В дополнение к контейнеру а-ля StringBuilder.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[7]: Подсчет ссылок в реализации std:
От: MaximE Великобритания  
Дата: 23.07.04 03:52
Оценка:
Шахтер wrote:

> Здравствуйте, c-smile, Вы писали:

>
> CS>Здравствуйте, Шахтер, Вы писали:
>
> Ш>>При копировании вектора создаётся копия данных. При копировании строк накручивается счётчик ссылок.
>
> CS>Это ты про std::string ?
>
> Ну почему. Про любую вменяемую реализацию строк.

Большинство "вменяемых" стандартных строк уже не используют reference counting (Mad COW Disease).

From Mechanism to Method: Distinctly Qualified

...
So deeply rooted is the idea that copy-on-write reference counting is mandatory for strings that many developers are shocked — and sometimes go into denial — when they discover that the return on investment in this technique is often negligible and sometimes negative. The long-standing belief in this old practice is, however, younger than faith in another more fundamental software engineering principle: separation of concerns. And hey, do we have concerns.
...


Reference Counting &mdash; Part III

...
Without atomic integer operations, copy-on-write typically incurs a significant performance penalty. Even with atomic integer operations, COW can make common String operations take nearly 50% longer -- even in single-threaded programs.

In general, copy-on-write is often a bad idea in multithread-ready code. In short, the reason is that the calling code can no longer know whether two distinct String objects actually share the same representation under the covers, and so String must incur overhead to do enough serialization that calling code can take its normal share of responsibility for thread safety. Depending on the availability of more-efficient options like atomic integer operations, the impact on performance ranges from "moderate" to "profound."
...


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 beta
Re[5]: Подсчет ссылок в реализации std:
От: ArtDenis Россия  
Дата: 23.07.04 04:03
Оценка: +1 -1
Здравствуйте, Шахтер, Вы писали:


AD>>Не все реализации std::string основаны на подсчёте ссылок. Для обычных std::string операция копировния по скорости аналогична std::vector<char>.

Ш>Это каких, обычных? Если реализация string клонирует строку при копировании, это значит -- кривая реализация.

Не спорю, свои приемущества в подсчёте ссылок есть. Особенно, если программист злоупотребляет такими констркуциями как:
void some_func(std::string arg1, std::string arg2) // так пишет "криворукий" программист :))
{

Или при сортировке строк. Правда, если переопределить функцию swap:
namespace std
{
  void swap(std::string & str1, std::string & str2)
    {
      str1.swap(str2);
    }
}

то это приемущество отпадает. Никаких других приемуществ я не знаю. Если я копирую одну строчку в другую, то то с вероятностью 95% я это делаю для её модификации, и подсчёт сылок мне нафиг не нужен.

AD>>Кроме того, для std::vector<char> мы гарантированно имеем неразрывную последовательность данных в памяти (иногда это бывает очень важно).


Ш>При работе со строками, обычно это неважно.

Когда как.
... << Rsdn@Home 1.1.4 beta 1 >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.