Как стать автором
Обновить

Комментарии 34

Спасибо! Очень интересно!

var s3 = " habra" + " habr";



Тут насколько я понимаю должно быть
var s3 = " habra" + "habr";

Спасибо за замечание. Не знал…
И еще вы зря смешали в одну кучу и С и С++ в исходном примере. Я думаю внутренняя реализация std::string куда ближе по внутреннему устройству к " basic string", хотя и с рядом существенных отличий.
Кошка — аналог принтера (правда с рядом существенных отличий)…
std::string (точнее говоря std::basic_string) так-же как и C#-ные «basic string» хранит помимо буффера строки, еще и размер, так-же позволяет нулевые символы посредине строки, так-же держит нулевой символ в конце буффера, не смотря на то, что самому классу он не нужен, но держит для совместимости со старыми C-API (т.е. по сути — ради c_str()). А различия представления строки только в том, что размер строки хранится не в нескольких байтах перед самой строкой, а отдельным полем класса std::basic_string

Более существенные отличия от C# в том, что std::string — mutable, и по этому реализует (на ряде платформ) такие фишки как например copy-on-write копирование строк, которые в C# просто не нужны.
это вы еще про разные реализации STL наверно невкурсе… а стоило бы… (например ms реализация может хранить небольшие строки в стеке, перенося их в кучу при увеличении и т.д.)…

кошка VS принтер:
Как и принтер кошка может занимать пространство на столе, является теплым (теплее чем окружающий воздух), в большом количестве времени ничего не делает (простаивает), потребляет некоторое количество рессурсов, её надо периодически чистить, может издавать звуки, и ее может тошнить потребляемым ресурсом…

На самом деле между строками C# и C++ столько же совпадений как и в приведенном мной примере.
Я не говорю что они совсем вот идентичны. Мой изначальный комментарий был про то, что не надо смешивать C и C++ строки, std::string куда ближе к C# строкам чем к C строкам.

Про то, как делает ms — извините, мало в курсе, т.к. большая часть опыта связана с не-windows платформами.
Эта оптимизация есть не только у MS, но и в кроссплатформенном STLPORT
  enum {_DEFAULT_SIZE = 4 * sizeof( void * )};
#if defined (_STLP_USE_SHORT_STRING_OPTIM)
  union _Buffers {
    _Tp*  _M_end_of_storage;
    _Tp   _M_static_buf[_DEFAULT_SIZE];
  } _M_buffers;
#else
  _Tp*    _M_end_of_storage;
#endif


Внутри объекта string есть буфер на 16 знаков (32 для x64) и если строка короткая, для её содержимого не выделяется дополнительно память вне объекта string.
По-моему, вы в тексте себе противоречите:
Использование неизменных строк ведет к снижению нагрузки на память, так как нет необходимости хранить 2 экземпляра одной строки. В таком случае и памяти меньше расходуется, и сравнение происходит быстрее, так как требует сравнение лишь ссылок

и
они неизменяемы и их сравнение происходит по значению, а не по ссылкам
На самом деле сравнивание сперва идет по ссылке, а потом (видемо в случае поломанного интернирования) так: paste.org.ru/?t6mbfn
Спасибо. Очень интересно и въедливо. Насколько я помню, чтобы работало переопределение Object.Equals, надо переопределить Object.GetHashCode.
«чтобы работало» надо его просто переопределить (override). Хорошей практикой является переопределение двух этих методов (для согласованности логики), но это не обязательно.
Смотря что подразумевается под «обязательно».
Есть такое понятие, как контракт на Equals. Он не контролируется компилятором, но подразумевается многими инструментами.
Ну пусть подразумевается. С чего бы это стало обязательным? Не путайте людей — есть стандарт языка — в нём всё обязательное прописано, а в остальном это «хорошая\плохая практика использования».
Если я правильно помню, GetHashCode() используется различными контейнерами типа HashSet или Dictionary для проверки существования ключа. Если переопределить только Equals, то работа с ними будет приводить к неожиданным результатам.
Что-то меня сглючило. Сослался на java.

Вот msdn:

A hash function must have the following properties:

If two objects compare as equal, the GetHashCode method for each object must return the same value.


То есть переопределяя Equals, вы обязаны переопределить GetHashCode, для соблюдения контракта, прописанного как обязательный в стандарте языка.
вы уверены что вы стандарт языка не путаете с справкой по .net framework? Кроме того переводчик из вас никакой, там речь про метод Equals() не ведется.
Хорошо, уели. В CSharp Language Specification этого действительно нет. Более того, этого нет даже в summary к Object, чему я крайне удивлен (в Java — есть).

На мой взгляд упоминание при людях, плохо разбирающихся в языке, что переопределять GetHashCode при переопределении Equals не обязательно, все-таки не стоит. Есть плохие практики, но эта просто ужасна.
Отличная статья, спасибо.
Вот еще интересно про интернирование строк: blogs.msdn.com/b/ruericlippert/archive/2009/09/28/string-empty.aspx
Остался только один вопрос:

string str1 = "habr";
string str2 = "habr";
Console.WriteLine(str1 == str2); 

Понятно что ответ true, но что произошло? Проверка по ссылке или по значению?
Здесь str1 и str2 будут ссылаться на один объект и проверка, видимо, будет по ссылке.
public static bool operator ==(string a, string b)
    Member of System.String

Таки по значению.
Точнее сначала по ссылке, потом по значению как оптимизированная реализация сравнения.

А вот если к Object привести, то по ссылке.
По идее, если у нас включено интернирование, и если метод Equals сначала проверяет по ссылке, то str1 и str2 в данном случае должны указывать на один объект. В таком случае пройдет проверка по ссылке.
Режим зануды: ON
Осталось вспомнить, что каждый символ в строке находится в UTF -16 кодировке значит, занимает так же 2 байта, следовательно

UTF-16 — кодировка с переменным количеством байт на символ. Либо 2, либо 4 байта.
Режим зануды: OFF
А зря вы OFF, это же очень существенно, например, сразу встает вопрос, что такое length: размер буффера или логическая длина, и в случае переменной длины символов уже нельзя просто получить одно из другого, надо хранить оба числа для O(1) получения. При том, что клиенту почти всегда нужна длина в символах, а для внутренней кухни часто требуется размер в байтах, и если хранится только одно число, то это серьезная просадка производительности.
Потому что UCS-2
если вы сериализуете полученную подстроку стандартными средствами и передаете её по сети, то будет сериализован весь оригинальный массив и количество передаваемых байтов по сети будет большим
Извините, но это полный бред. Больше похоже на грязную рекламу типа: посмотрите как в яве отстойно и как в донете круто. В Sun/Oracle не настолько тупые люди работают, чтобы не предусмотреть специальный случай для сериализации строк. Разве так сложно это проверить 5-ю строчками кода, перед тем как писать в статье?
НЛО прилетело и опубликовало эту надпись здесь
Во-первых это не бред. Мой вывод был сделан на основании реализации метода substring который до последней версии возвращал ссылку на текущий массив символов.
Во-вторых это не реклама и тем более не грязная реклама. Ведь никто не говорит, что в .NET строки реализованы лучше чем в Java!
В-третьих не думаю, что в Sun/Oracle работают тупые люди.
В-четвертых реализация строкового типа в последней версии Java поменялась и теперь она похожа на поведение в .NET.
Мой вывод был сделан на основании реализации метода substring который до последней версии возвращал ссылку на текущий массив символов.
Ну нельзя же на основе только метода substring делать вывод о сериализации! Это как-то глупо. Разве не логично глянуть реализацию сериализации? Ну или хотя бы просто проверить.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации