LINUX.ORG.RU

C++ и std::string


1

1

В очередной раз потребовалось нечто большее что может std::string, а именно split. Возникла идея написать свой класс String с блэкджеком, в рамках проекта. Можно также использовать прекрасный QString, который все может и имеет прекрасные интерфейсы, но тянуть что-то из Qt отдельно не хочется.
А как вы боретесь с беднотой std::string?

лучше напиши функцию, чтоб в проекте везде были стандартные строки, либо бери QtCore

П.С. сам предпочитаю работать с char*

wota ★★ ()
Ответ на: комментарий от wota

Да, наверное заведу какой-нибудь namespace с функциями для строк, хотя мне кажется это не очень красиво с точки зрения ООП. (возможно я ошибаюсь =))

sol_linux ★★ ()

пейсать свои классы. я и от убожества list<T> отказался, написал свой класс списка на базе массива со сложность доступа O(1).

anonymous ()
    string s("A bulk of shit hits the fan");
    istringstream iss(s);

    do {
        string sub;
        iss >> sub;
        cout << "Substring: " << sub << endl;
    } while (iss);
shty ★★★★★ ()
Последнее исправление: shty (всего исправлений: 1)
Ответ на: комментарий от anonymous

я и от убожества list<T> отказался, написал свой класс списка на базе массива со сложность доступа O(1).

кококо, а какая у тебя сложность добавления в начало списка, а в середину? :)

shty ★★★★★ ()
Последнее исправление: shty (всего исправлений: 1)

В очередной раз потребовалось нечто большее что может std::string, а именно split. Возникла идея написать свой класс String с блэкджеком, в рамках проекта

а напиши, это всегда полезно, если не писал, только не пиши по колхозному, используй аллокаторы

shty ★★★★★ ()

Я со строками работаю уровнем выше, в питоне - там split есть;-)

AIv ★★★★★ ()
Ответ на: комментарий от shty

для моих целей важно добавление в конец и скорость доступа к элементу.

anonymous ()
Ответ на: комментарий от shty
    } while (!iss.eof());

fixed

Иначе цикл повторяется ещё раз на уже пустом потоке (когда iss уже eof(), но ещё good() :)

static_lab ★★★★★ ()

А в std::string и не должно быть всё-всё-всё. Класс легко расширяется внешними функциями. Лучше всего оформить их в качестве шаблонов. Если совсем грустно и хочется чтобы split был в составе клаасса, то можно сделать класс basic_extended_string<> наследником std::basic_string<>. Ну и два тайпдефа: estring и westring. Это решение хоть и горбатое, но зато сохранит преемственность с классом строки.

Qt --- штука хорошая. Я её искренне и нежно люблю. Но увы и ах: применять классы Qt в не-Qt-проектах почти нереально. В частности не забываем, что в Qt строка --- это массив QChar. И при обращении к функциям ввода-вывода каждый раз будут требоваться не вполне тривиальные преобразования.

Boost --- на любителя. Я не он =)

Решение за Вами.

ssvda ()
Ответ на: комментарий от anonymous

для моих целей важно добавление в конец и скорость доступа к элементу.

а для каких целей потребовалось пытаться обсирать std::list?

shty ★★★★★ ()
Ответ на: комментарий от ssvda

можно сделать класс basic_extended_string<> наследником std::basic_string<>

а разве stl-контейнеры можно наследовать?

shty ★★★★★ ()
Ответ на: комментарий от shty

а разве stl-контейнеры можно наследовать?

вроде как можно, только в деструкторе нудо будет руками дернуть деструктор родителя

wota ★★ ()
Ответ на: комментарий от wota

можно то можно, но стандартные контейнеры не предназначены для наследования

vvviperrr ★★★★★ ()
Ответ на: комментарий от shty

А кто-то это запрещал? Классы как классы.

Другое дело, что для них по большому счёту определены только интерфейсы, а реализация --- чёрный ящик. Так что если в классе наследнике опираться только на описанные в стандарте функции, то всё будет работать.

ssvda ()
Ответ на: комментарий от Reset

зачем?

спроси у авторов комментариев выше по топику

wota ★★ ()
Ответ на: комментарий от wota

только в деструкторе нудо будет руками дернуть деструктор родителя

o_O Зачем? Вообще-то язык гарантирует правильную последовательность вызова деструкторов при классов при наследовании. Если это сделать, то деструктор родителя будет вызван дважды. Вряд ли родителю это понравится =)

Классы контейнеров ни чем не отличаются от любых других классов. Стандарт лишь фиксирует требования к ним (имена, набор членов и что эти члены делают). Их код всегда можно посмотреть: они написаны на стандартном C++.

ssvda ()
Ответ на: комментарий от wota

Я не про наследование, а про вызов деструктора руками.

Reset ★★★★★ ()
Ответ на: комментарий от wota

не, ну технически то можно, но это ж бесполезно, по смыслу это будет то же самое что написать враппер, не?

shty ★★★★★ ()

контора не одобряет «лишние», по их мнению библиотеки, так что пишется неймспейс типа StringsUtils и туда кидаются всякие сплиты:

std::vector<std::string> &split(const std::string &str, char delim, std::vector<std::string> &ret)
{
    std::stringstream ss(str);
    std::string s;

    while(std::getline(ss, s, delim))
        ret.push_back(s);

    return ret;
}

std::vector<std::string> split(const std::string &str, char delim)
{
    std::vector<std::string> ret;
    return split(str, delim, ret);
}

vvviperrr ★★★★★ ()
Ответ на: комментарий от ssvda

Так что если в классе наследнике опираться только на описанные в стандарте функции, то всё будет работать.

не все - виртуального деструктора там нет, так что если скастовать твой класс к std::string, то деструктор твоего класса не вызовется

wota ★★ ()
Ответ на: комментарий от ssvda

язык гарантирует правильную последовательность вызова деструкторов при классов при наследовании

эээ.... man virtual destructor?

nanoolinux ★★★★ ()
Ответ на: комментарий от Reset

Я не про наследование, а про вызов деструктора руками.

а..., то мне уже спать пора, то я хотел сказать, что после каста к std::string «потеряется» деструктор, но в итоге написал что-то левое

wota ★★ ()
Ответ на: комментарий от Norgat

Очевидно, потому что он хотел обосрать STL, но не вышло...

Kosyak ★★★★ ()

Я для таких целей создаю класс String со статическими, выполняющими недостающий функционал методами, например:

#include <string>
#include <list>

class String
{
  static std::list<std::string> split(const std::string& str, const std::string& delimeter)
  {
    // ...
  }
};

В результате API проекта не завязывается на «нестандартные» компоненты ибо делать своего наследника std::string становится не нужно. Но все, очевидно, субъективно, посему всяк по своему видит...

illy ()

даже без плюсов

#ifdef WIN32
  token1 = strtok_s(line, search, &context);
  token2 = strtok_s(NULL, search, &context);
#else
  token1 = strtok(line, search);
  token2 = strtok(NULL, search);
#endif
nCdy ()
Ответ на: комментарий от ssvda

сделать класс basic_extended_string<> наследником std::basic_string<>

в basic_string<> деструктор невиртуальный

DELIRIUM ★★★★★ ()
Ответ на: комментарий от ssvda

можно сделать класс basic_extended_string<> наследником std::basic_string<>

нельзя

jtootf ★★★★★ ()

Пользуюсь QString, ибо он умеет гораздо больше, чем просто split. Тянуть из-за него одного Qt конечно не весело, но ничего вменяемее просто не существует.

m0rph ★★★★★ ()
Ответ на: комментарий от jtootf

а разве, если наследник не содержит своих атрибутов, то всё равно нельзя?

anonymous ()
Ответ на: комментарий от anonymous

А завтра тебе понадобится нечто большее чем сплит, что тогда? Зачем велосипеды, если есть бесплатные феррари

Boui ()

C++ vs. C

C++:

В очередной раз потребовалось нечто большее что может std::string, а именно split. Возникла идея написать свой класс String с блэкджеком, в рамках проекта. Можно также использовать прекрасный QString, который все может и имеет прекрасные интерфейсы, но тянуть что-то из Qt отдельно не хочется.

в бусте есть split

лучше напиши функцию, чтоб в проекте везде были стандартные строки, либо бери QtCore

пейсать свои классы.

istringstream iss(s);
string sub;
iss >> sub;

в питоне - там split есть;-)

Класс легко расширяется внешними функциями. Лучше всего оформить их в качестве шаблонов. Если совсем грустно и хочется чтобы split был в составе клаасса, то можно сделать класс basic_extended_string<> наследником std::basic_string<>. Ну и два тайпдефа: estring и westring.

пишется неймспейс типа StringsUtils и туда кидаются всякие сплиты:
std::vector<std::string> &split(const std::string &str, char delim, std::vector<std::string> &ret)

Я для таких целей создаю класс String со статическими, выполняющими недостающий функционал методами,

boost::tokenizer

Пользуюсь QString, ибо он умеет гораздо больше, чем просто split. Тянуть из-за него одного Qt конечно не весело, но ничего вменяемее просто не существует.



========================= vs ==============================


C:

The GNU C Library

5 String and Array Utilities 
5.7 Search Functions 
5.7.1 Compatibility String Search Functions

Function: char * strchr (const char *string, int c)
Function: char * strstr (const char *haystack, const char *needle)
Function: size_t strspn (const char *string, const char *skipset)
Function: size_t strcspn (const char *string, const char *stopset)
Function: char * strpbrk (const char *string, const char *stopset)

5.8 Finding Tokens in a String

Function: char * strtok_r (char *newstring, const char *delimiters, char **save_ptr)
Function: char * strsep (char **string_ptr, const char *delimiter)
LamerOk ★★★★★ ()
Ответ на: C++ vs. C от LamerOk

C++:

static string foo( const string& msg  )
{
    return "HTTP/1.1 200 OK\r\n" + msg;
}

int main()
{
    cout << foo( "0" );
}

C:

?

wota ★★ ()
Ответ на: C++ vs. C от LamerOk

или даже банальное:

C++:

return string( "14" ).insert( 1, "23" );

C:

?

П.С. от К.О.: у строк в С++ есть большой плюс - не надо думать об аллокации, переаллокации, копировании и освобождении памяти, а также о хранении и передачи отдельно длины строки, а еще один плюс - с ними можно работать все теми же «String and Array Utilities», если понимать что делаешь, минус - нет методов на все случаи жизни, как и в С функций - представленный выше набор не идет ни в какое сравнение с тем же Qt

wota ★★ ()
Ответ на: комментарий от vvviperrr

gstring например

C++ + Qt:

QStringList foo( QString str )
{
    return str.split( "," );
}

void foo2( QStringList names )
{
    for( auto name : names )
        cout << name;
}

int main()
{
    foo2( foo( "A,B,C" ) );
}

C + GLIB:

?

wota ★★ ()
Ответ на: комментарий от wota

а теперь посчитай сколько ты объектов создал вместо того чтоб вызвать strcat?

anonymous ()
Ответ на: комментарий от anonymous

а теперь посчитай сколько ты объектов создал вместо того чтоб вызвать strcat?

а не надо экономить на спичках, создание объекта на стеке (без тяжелого конструктора) - практически ничто, а выделение памяти под строки точно так же придется делать и в С, strcat к пустому месту не применишь

wota ★★ ()
Ответ на: комментарий от wota

про то что strcat не рекомендуется использовать из-за потенциальных багов и говорить не стоит

wota ★★ ()
Ответ на: комментарий от wota

как и про то, что strcat честно побайтово будет сканить строку, вместо того, что использовать memcpy, которые не должен этого делать и следовательно имеет больше возможностей для оптимизации

wota ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.