[C++] Как вым добавочка к интерфейсу string'а?

Werdna


class string
{
...
public:
char *operatorvoid);
};

Эта штука делает дубликат строки и возвращает указатель на него.
Возник спор — это хорошо или плохо?

Flack_bfsp

А в чём добавочка-то?
В stl-ном стринге это делается методом c_str

ppplva

c_str дает константную строку

Werdna

тут даже не сколько константная, сколько сам оператор красив.
Пусть будет так:
 
const char *operatorvoid);

ppplva

Если это эквивалентно c_str, то лучше не надо. Имхо, ухудшается читабельность кода.

Werdna

Читабельность не ухудшается. А вот зато стринг сможешь как параметр chost char* передавать.

ppplva

Приписав к нему круглые скобки ? Спасибо, я лучше c_str напишу.
К тому же, вызванная функция должна освободить память из-под строки - если она все же дублируется. Это неочевидно из записи str и, к тому же, не всегда желательно.

smit1

>вызванная
Вызвавшая?
По существу: втопку. Пусть лучше у стринга оператор форматирует жосский диск, или печатает "ХУЙ"!

ppplva

>вызванная
Вызвавшая?
Если я правильно понял, предлагается использовать этот оператор для передачи строки как const char*, то есть
void f(const char*);
std::string s;
f(s;

Тогда освободить память может только вызванная функция.

Flack_bfsp

А каким образом она высвободит память, если эта память нужна после её завершения?
Короче, идея автора треда - отстой.

Olyalyau

Ничего подобного не добавили в стандарт потому, что строки будут без дополнительных указаний сами кастоваться в char*. Это плохо по двум причинам — во-первых повышает неоднозначность перегрузки. Компилятор не будет знать, какой из конструкторов использовать std::string(const std::string &) или std::string (const char * const) при конструировании строки по одному строковому аргументу. Аналогично для других операций, которые перегружены для std::string и char *. Во-вторых, от char * в идеологии C++ идёт отказ, так как этот тип заведомо не может предоставить возможностей контроля, например, за выходом за границы его памяти. Этот тип не может содержать внутренние нули, и по этому сам по себе не приемлем для хранения бинарных данных (надо дополнительно хранить размер и следить за его актуальностью). Этот тип вынуждает пользователя всегда контролировать работу с памятью самостоятельно. И т.д.
Есть ещё одна проблема: кто будет освобождать память, выделенную твоим оператором преобразования строки в char*? Строка? Или ты? Если строка, то ты не сможешь менять размер строки, на которую указывает этого char*. Если ты — то будут утечки памяти. Как показал опыт, в случаях, когда память выделяется функцией, а освобождаться должна вызываемой стороной, вызывающая сторона обычно забывает освободить память. Далее, память должна быть освобождена парным способом, к способу аллокации. Какой способ аллокации у std::string? Тебя это сильно удивит, но не new[] и не malloc. Поэтому, удаление этой памяти через delete/delete[]/free/realloc будет заведомо некорректным. Может быть помещать результат в статической памяти? Тогда программа будет заведомо не thread-safe, а строки в char* можно будет кастовать только если их размер не превышает размера статического буфера. Последнее не исправляется даже за счёт thread-specific storage (__thread, если твой компилятор, линкер и среда запуска приложений поддерживают такое).

evgen5555

string - это не интерфейс

Realist

-1
В дополнение к Serezhе
string s1,s2;
....
s1+s2 — конкатенация
// очепятка:
s1-s2 — разность адресов, проблемы с памятью.
Этот вопрос обсуждаетсяв книге у Саттера. Могу посмотреть точную ссылку, но суть уже изложили тут.

Werdna

Компилятор не будет знать, какой из конструкторов использовать std::string(const std::string &) или std::string (const char * const) при конструировании строки по одному строковому аргументу.

Да, пожалуй самый существенный аргумент. Кроет всё.

mira-bella

Ничего подобного не добавили в стандарт потому, что строки будут без дополнительных указаний сами кастоваться в char*. Это плохо по двум причинам — во-первых повышает неоднозначность перегрузки. Компилятор не будет знать, какой из конструкторов использовать std::string(const std::string &) или std::string (const char * const) при конструировании строки по одному строковому аргументу. Аналогично для других операций, которые перегружены для std::string и char *.
хм
впервые вижу гонево вашего авторства
1. Какое отношение перегрузка оператора скобочки имеет к неявному преобразованию типов? Преобразование типов определяется либо конструкторами, либо определением оператора с названием типа, в который происходит преобразование
foo_class::operator foo_type;

а это:
foo_class::operator...)

здесь не причем.
2. Даже если определить преобразование типа std::string в const char*, все равно никакой неоднозначности при вызове

std::string s;
foo(s);

при наличии функций

foo(const char* const)
foo(const std::string&)

не будет.
Ботайте правила разрешения таких неоднозначностей (преобразование в ссылку или в константу более приоритетно чем любое другое неявное преобразование).
Впрочем то, что определять такое неявное преобразование как std::string в const char* - очень плохая идея, это несомненно по многим причинам, включая изложенные вами.
Какой способ аллокации у std::string? Тебя это сильно удивит, но не new[] и не malloc. Поэтому, удаление этой памяти через delete/delete[]/free/realloc будет заведомо некорректным.
способ аллокации std::string - это std::allocator<char>

который реализован именно через new/delete
но конечно в любом случае возвращать из функции динамически выделенную память, которую должен освобождать пользователь - неприемлемо для стандартной библиотеки (и очень плохая идея для любой другой библиотеки)
к остальному +1

Realist

Виноват, невнимательно прочитал предложение.
Мой предыдущий пост касается приведения типов.
Оператор круглые скобки имеет сделан для того, чтобы объекты вели себя подобно функциям. Преобразование в char* — это не тот случай. Так что предложение не соответствует концепции оператора . Читаемость кода ухудшается, потому как из кода неясно, что этот оператор возвращает. Лучше дописать c_str.
Комментарии про выделение/освобождение памяти не рулят, потому как они настолько же применимы и к c_str

Flack_bfsp

Оператор круглые скобки имеет сделан для того, чтобы

Ниасилил твой русский язык.
Комментарии про выделение/освобождение памяти не рулят, потому как они настолько же применимы и к c_str
Ошибаешься. c_str не выделяет новую память, и вызывающая функция не должна ничего освобождать.
Попробуй такой код:
 	std::string s("111");
const char *c = s.c_str;
printf("s = %s\n", s.c_str;
printf("c = %s\n", c);
s.append("22");
printf("s = %s\n", s.c_str;
printf("c = %s\n", c);

c указывает на то же место, что и s. Никаких проблем с памятью.

Landstreicher

> Ошибаешься. c_str не выделяет новую память, и вызывающая функция не должна ничего освобождать.
+1

Realist

Согласен, я затупил

mira-bella

Оператор круглые скобки сделан для того, чтобы объекты вели себя подобно функциям. Преобразование в char* — это не тот случай. Так что предложение не соответствует концепции оператора . Читаемость кода ухудшается, потому как из кода неясно, что этот оператор возвращает.
+1
именно так

Olyalyau

хм
впервые вижу гонево вашего авторства
1. Какое отношение перегрузка оператора скобочки имеет к неявному преобразованию типов? Преобразование типов определяется либо конструкторами, либо определением оператора с названием типа, в который происходит преобразование
code:operator foo_type;
а это:
code:operator...)
здесь не причем.
Согласен. Но, насколько я понял, в первом посте треда имел в виду именно оператор неявного приведения типа. По крайней мере его слова
А вот зато стринг сможешь как параметр chost char* передавать.

(в одном из следующих постов) наводят на такие мысли.
2. Даже если определить преобразование типа std::string в const char*, все равно никакой неоднозначности при вызове
code:
std::string s;
foo(s);
при наличии функций
code:
foo(const char* const)
foo(const std::string&)
не будет.
Ботайте правила разрешения таких неоднозначностей (преобразование в ссылку или в константу более приоритетно чем любое другое неявное преобразование).

Возможно, я не достаточно хорошо знаю стандарт. Но у меня возникали проблемы с неоднозначностью перегрузки именно когда класс А имел конструктор от типа B и оператор преобразования в этот тип B. Неоднозначности возникали при попытке разрешить смешанные операции +, -, ... Возможно с тех пор стандарт поменяли, компилятор исправили, ...
Какой способ аллокации у std::string? Тебя это сильно удивит, но не new[] и не malloc. Поэтому, удаление этой памяти через delete/delete[]/free/realloc будет заведомо некорректным.
code:способ аллокации std::string - это std::allocator<char>
который реализован именно через new/delete

Память, выделенную через аллокатор и освобождать надо через аллокатор. И не в коем случае, не через delete. Вне зависимости от того как написан аллокатор и специфицирована ли его реализация стандартом.

Olyalyau

Ошибаешься. c_str не выделяет новую память, и вызывающая функция не должна ничего освобождать.
Ошибаешься ты. Стандарт не запрещает c_str как и data выделять память, но требует от пользователя не менять память и не использовать её после того, как сама строка удалена или для неё вызван не-константный метод. Это позволяет реализовать c_str/data как с выделением памяти (например, если строка может хранить своё содержимое не последовательно в памяти, как rope; или, например, если строки реализованы с отложенным копированием copy-on-write так и без него. Единственно что — если строка выделяет память, то она же её и освободит.

Flack_bfsp

если строка выделяет память, то она же её и освободит
Ну да, ключевая половина в моём предложении - вторая.
Оставить комментарий
Имя или ник:
Комментарий: