Это уже совсем как-то нехорошо получается. С копированием содержимого pascal-строки во внешний буфер я ещё могу согласиться, но модифицировать состояние объекта для возврата указателя на буфер...
Вообще, идея возвращать с-строку или string, в данном случае порочна. Здесь как бы сбивает с толку термин "Pascal-строка". На самом деле это не строка, хотя и может успешно выступать в качестве текстовой строки. Если быть точным, то то PascalString — это массив байт. И его надо рассматривать именно в этом ракурсе.
Содержимое PascalString может быть любым. Содержимое с-строки не должно содержать символ '\0' внутри строки, но этот символ обязан быть в конце строки. Здесь отличие на уровне идеи, а не реализации.
Это уже совсем как-то нехорошо получается. С копированием содержимого pascal-строки во внешний буфер я ещё могу согласиться, но модифицировать состояние объекта для возврата указателя на буфер... Вообще, идея возвращать с-строку или string, в данном случае порочна.
std::string чем не пример?
А в новом стандарте даже в векторе возвращается без проблем. Если клиент не дурак, то не будет пытаться её разрушить.
Да и вообще, такая строка годится только для внутренностей программы, а при использовании какого-нибудь API придется всё-равно выдавать указатель на буфер.
Да и вообще, такая строка годится только для внутренностей программы, а при использовании какого-нибудь API придется всё-равно выдавать указатель на буфер.
У-у-упс! А вот с этого места поподробнее.
А как же один из основных принципов ООП? Как с инкапсуляцией?
А как же один из основных принципов ООП? Как с инкапсуляцией?
А ничего, что C++ не соответствует концепции ООП? Или соответствует, но далеко не полностью.
У-у-упс! А вот с этого места поподробнее.
большинство API имеют си-шные интерфейсы, значит туда нужно будет всё равно передавать буфер. Будет ли эффективно выделять память при каждом чихе и копировать туда строку? В большинстве случаем нужно лишь чтение строки, а не запись в нее, а значит лучше будет просто вернуть указатель на константу.
Ребята, может мне только кажется, но это мой взгляд со стороны.
Все вообще начиналось с постановки задачи не использовать никаких библиотек.
Но как всегда cstring подвернулась под руку, а как же без cstdlib, а string — тут без нее совсем не обойтись. :)))
Может быть задача поставлена неправильно, а может не туда пошли. ХЗ?
Ребята, может мне только кажется, но это мой взгляд со стороны.
Все вообще начиналось с постановки задачи не использовать никаких библиотек.
Но как всегда cstring подвернулась под руку, а как же без cstdlib, а string — тут без нее совсем не обойтись. :)))
Может быть задача поставлена неправильно, а может не туда пошли. ХЗ?
Alf, cstring используется только для того, чтобы можно было создать метод cpp_str()( который, видимо придётся убрать ), больше ничего из этой библиотеки не используется, так что можно сказать, что её нет.
cstdlib вообще нигде не используется( использовалась в ранних версиях для выделения памяти, или выделение памяти тоже написать самому? :) ), я просто забыл её удалить. Поэтому не волнуйся :)
А ничего, что C++ не соответствует концепции ООП? Или соответствует, но далеко не полностью.
Во-первых, что ты имеешь ввиду под несоответствием С++ концепции ООП?
Во-вторых, концепция — это концепция. В духе ООП можно писать программы и на pure-C и на ассемблере. Концепция — это для человека, а не для инструмента.
большинство API имеют си-шные интерфейсы, значит туда нужно будет всё равно передавать буфер.
Я бы сказал даже сильнее: нет ни одного API (и, наверное, никогда не будет), который использовал бы класс PascelString ))
Частично согласен с твоим предложением. Наверное оптимальным решением будет метод:
const char *data() const { return str; }
В классе PascalString критичным элементом, отвечающим за непротиворечивость данных класса является len. И именно его модификацию нельзя допускать извне.
PS. Кстати, при разработке класса незаслуженно обойдён вниманием вопрос сериализации. porshe, вопрос к тебе, как к основному разработчику: как записать в файл объект типа PascalString, и как его оттуда (из файла) восстановить?
Я тут внёс небольшие изменения, в результате появилась новая версия.( опять на облаке майл, да не обидится на меня selevit, большое ему спасибо за материал, я его потихоньку читаю ).
Если не помогать функции get() (вариант (1)), то совсем плохо.
Если помогать (вариант (2)), третья переменная восстанавливается неправильно (из-за '\0' в середине).
С оператором << опять таки вопрос возникает: как быть, если в массиве байт есть непечатные символы? Ты же наверное обратил внимание, как я извернулся при написании метода iLog(). Здесь надо принять решение как будет правильно: тупо выводить в поток «как есть» или делать преобразование непечатных символов. (Здесь я не настаиваю в правильности первого или второго решения.) Но в любом случае operator << и get() для сериализации не подходят.
В бинарном режиме можно сначала записать количество байт, а потом уже сами байты.
Это более здравая мысль. Но, я не нашёл реализации ((
В последней версии( см. ниже ), где немного исправлен метод get(), результат получился тот же, что и у класса string из стандартной библиотеки. Это я к тому, что, ИМХО, забота о правильном чтении из файла должна ложиться на плечи пользователя.
Хотя можно сделать так же, как и в бинарном режиме( с входным и выходным потоком соответственно ), сначала записываем количество, а потом саму строку, для входного потока делать то же самое, только читать. В этом случае можно для потоков cin и cout сделать исключение, не выводить количество символов для потока cout и не спрашивать то же самое для cin.
С оператором << опять таки вопрос возникает: как быть, если в массиве байт есть непечатные символы? Ты же наверное обратил внимание, как я извернулся при написании метода iLog(). Здесь надо принять решение как будет правильно: тупо выводить в поток «как есть» или делать преобразование непечатных символов. (Здесь я не настаиваю в правильности первого или второго решения.) Но в любом случае operator << и get() для сериализации не подходят.
Показывать непечатаемые символы, мне кажется нехорошо. Потому что это уже и не строка вовсе а смесь строки с массивом байт. Если же рассматривать класс PascalString именно как строку, то тогда нужно печатать так, как есть. Если же выводить непечатаемые символы цифрами, то тогда придётся рассматривать класс как массив байт, но ведь по заданию у нас строка.
В бинарном режиме можно сначала записать количество байт, а потом уже сами байты.
Это более здравая мысль. Но, я не нашёл реализации ((
По-моему, это лучше сделать пользователю класса.
Ты вообще-то тестировал свой код? Или как написалось, так и выложил?
Тема поднадоела? Тем более, что selevit запустил новую разминку ;-)
На закуску выкладываю свой PascalString. Не как образец, но как вариант. Тоже не без шероховатостей, но допиливать лень ))
Впрочем, вроде работает ))
По функциональности класс почти аналогичен реализации от porshe. Не реализовывал метод get(): считаю, что при необходимости вызывающий код может считать строку в буфер char* или в string, а потом передать классу в виде const char*. Зато добавлены методы для чтения и записи в двоичном режиме — read() и write() соответственно.
Мне так показалось. В обсуждении нет былого энтузиазма ))
Некоторые задачи, типа разработки библиотечного класса, как правило, требуют тщательного тестирования и длительного допиливания. Что есть уже не творчество, а рутина.
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Это уже совсем как-то нехорошо получается. С копированием содержимого pascal-строки во внешний буфер я ещё могу согласиться, но модифицировать состояние объекта для возврата указателя на буфер...
Вообще, идея возвращать с-строку или
string
, в данном случае порочна. Здесь как бы сбивает с толку термин "Pascal-строка". На самом деле это не строка, хотя и может успешно выступать в качестве текстовой строки. Если быть точным, то то PascalString — это массив байт. И его надо рассматривать именно в этом ракурсе.Содержимое PascalString может быть любым. Содержимое с-строки не должно содержать символ '\0' внутри строки, но этот символ обязан быть в конце строки. Здесь отличие на уровне идеи, а не реализации.
std::string чем не пример?
А в новом стандарте даже в векторе возвращается без проблем. Если клиент не дурак, то не будет пытаться её разрушить.
Да и вообще, такая строка годится только для внутренностей программы, а при использовании какого-нибудь API придется всё-равно выдавать указатель на буфер.
У-у-упс! А вот с этого места поподробнее.
А как же один из основных принципов ООП? Как с инкапсуляцией?
А ничего, что C++ не соответствует концепции ООП? Или соответствует, но далеко не полностью.
большинство API имеют си-шные интерфейсы, значит туда нужно будет всё равно передавать буфер. Будет ли эффективно выделять память при каждом чихе и копировать туда строку? В большинстве случаем нужно лишь чтение строки, а не запись в нее, а значит лучше будет просто вернуть указатель на константу.
Ребята, может мне только кажется, но это мой взгляд со стороны.
Все вообще начиналось с постановки задачи не использовать никаких библиотек.
Но как всегда
cstring
подвернулась под руку, а как же безcstdlib
, аstring
— тут без нее совсем не обойтись. :)))Может быть задача поставлена неправильно, а может не туда пошли. ХЗ?
Alf,
cstring
используется только для того, чтобы можно было создать методcpp_str()
( который, видимо придётся убрать ), больше ничего из этой библиотеки не используется, так что можно сказать, что её нет.cstdlib
вообще нигде не используется( использовалась в ранних версиях для выделения памяти, или выделение памяти тоже написать самому? :) ), я просто забыл её удалить. Поэтому не волнуйся :)Во-первых, что ты имеешь ввиду под несоответствием С++ концепции ООП?
Во-вторых, концепция — это концепция. В духе ООП можно писать программы и на pure-C и на ассемблере. Концепция — это для человека, а не для инструмента.
Я бы сказал даже сильнее: нет ни одного API (и, наверное, никогда не будет), который использовал бы класс PascelString ))
Частично согласен с твоим предложением. Наверное оптимальным решением будет метод:
В классе
PascalString
критичным элементом, отвечающим за непротиворечивость данных класса являетсяlen
. И именно его модификацию нельзя допускать извне.PS. Кстати, при разработке класса незаслуженно обойдён вниманием вопрос сериализации. porshe, вопрос к тебе, как к основному разработчику: как записать в файл объект типа
PascalString
, и как его оттуда (из файла) восстановить?Ну так организовать запись в поток, или же писать в файл
У меня есть перегруженный оператор
<<
который работает с потоком вывода, и методget
, который работает с потоком ввода.В бинарном режиме можно сначала записать количество байт, а потом уже сами байты.
Я тут внёс небольшие изменения, в результате появилась новая версия.( опять на облаке майл, да не обидится на меня selevit, большое ему спасибо за материал, я его потихоньку читаю ).
porshe,
Не работает ((
Если не помогать функции
get()
(вариант (1)), то совсем плохо.Если помогать (вариант (2)), третья переменная восстанавливается неправильно (из-за '\0' в середине).
С оператором
<<
опять таки вопрос возникает: как быть, если в массиве байт есть непечатные символы? Ты же наверное обратил внимание, как я извернулся при написании методаiLog()
. Здесь надо принять решение как будет правильно: тупо выводить в поток «как есть» или делать преобразование непечатных символов. (Здесь я не настаиваю в правильности первого или второго решения.) Но в любом случаеoperator <<
иget()
для сериализации не подходят.Это более здравая мысль. Но, я не нашёл реализации ((
Плюха, приводящая к вылету программы:
Мораль: не называйте формальные аргументы так же, как и члены класса.
Тоже интересный код:
Компилятор, наверное, соптимизирует. Но зачем писать так?
Что будет, если вызовут с -1?
И здесь
void PascalString::resize ( int size )
аналогично.В
resize()
порадовало:Вообще-то
len - (len - size)
<=>size
, если раскрыть скобки ))Операторы
<
,>
ведут себя оригинально. Делается сравнение по короткой строке. Но для строк «123» и «12345», я бы сказал, что последняя больше.Ещё ляпа:
Ещё ляпа:
Сравниваем одни значения, а возвращаем разность других значений.
Ты вообще-то тестировал свой код? Или как написалось, так и выложил?
В последней версии( см. ниже ), где немного исправлен метод
get()
, результат получился тот же, что и у классаstring
из стандартной библиотеки. Это я к тому, что, ИМХО, забота о правильном чтении из файла должна ложиться на плечи пользователя.Хотя можно сделать так же, как и в бинарном режиме( с входным и выходным потоком соответственно ), сначала записываем количество, а потом саму строку, для входного потока делать то же самое, только читать. В этом случае можно для потоков
cin
иcout
сделать исключение, не выводить количество символов для потокаcout
и не спрашивать то же самое дляcin
.Показывать непечатаемые символы, мне кажется нехорошо. Потому что это уже и не строка вовсе а смесь строки с массивом байт. Если же рассматривать класс
PascalString
именно как строку, то тогда нужно печатать так, как есть. Если же выводить непечатаемые символы цифрами, то тогда придётся рассматривать класс как массив байт, но ведь по заданию у нас строка.По-моему, это лучше сделать пользователю класса.
Да, как написалось, так и выложил :-[
Вот исправленный код.
Тема поднадоела? Тем более, что selevit запустил новую разминку ;-)
На закуску выкладываю свой
PascalString
. Не как образец, но как вариант. Тоже не без шероховатостей, но допиливать лень ))Впрочем, вроде работает ))
По функциональности класс почти аналогичен реализации от porshe. Не реализовывал метод
get()
: считаю, что при необходимости вызывающий код может считать строку в буферchar*
или вstring
, а потом передать классу в видеconst char*
. Зато добавлены методы для чтения и записи в двоичном режиме —read()
иwrite()
соответственно.PasString.h
PasString.cpp
PS. Было бы неплохо еще расставить
noexcept
(С++11) илиthrow(PascalStringException)
...Почему вы так решили?
Мне так показалось. В обсуждении нет былого энтузиазма ))
Некоторые задачи, типа разработки библиотечного класса, как правило, требуют тщательного тестирования и длительного допиливания. Что есть уже не творчество, а рутина.
Впрочем, я не против продолжить обсуждение.
И я не против, но по какой теме? :)
многопоточность ;) строка должна уверенно вести себя и в многопоточном приложении
неее, такое я ещё не проходил :)
Кстати, да. Многопоточность — вообще тема очень нужная, советую покопать в эту сторону porshe и другим интересующимся.