Строки C++ без <string> и STL

Я не очень много использовал C++ в прошлом, а в последнее время много занимаюсь C#, и мне очень трудно снова вернуться к основам C++. Это особенно сложно, поскольку работа требует, чтобы нельзя было использовать ни одну из самых удобных конструкций C++, поэтому все строки должны быть char *, а списки STL не предусмотрены.

Что я сейчас пытаюсь сделать, так это создать список строк, что не займет у меня времени, используя STL или C#. В основном я хочу иметь такую ​​функцию, как:

char **registeredNames = new char*[numberOfNames];

Потом,

RegisterName(const * char const name, const int length)
{
    //loop to see if name already registered snipped
    if (notFound)
    {
        registeredNames[lastIndex++] = name;
    }

}

или, если это был C# ...

if (!registeredNames.Contains(name))
{
    registeredNames.Add(name);
}

и я понимаю, что это не работает. Я знаю, что константная природа переданных переменных (константный указатель и константная строка) делает это довольно трудным, но моя основная проблема в том, что я всегда избегал этой ситуации в прошлом, используя списки STL и т. д., Поэтому я никогда не пришлось это обойти!

Чем не работает?

benefactual 18.09.2008 15:25

Кстати, в объявлении RegisterName должно быть «const char * const name», а не «const * char const name».

Greg Rogers 18.09.2008 17:31

Так что вы на самом деле занимаетесь программированием на C?

Sanjaya R 07.11.2008 20:35

Либо вам запрещено по какой-то странной причине не использовать STL, и тогда вы должны писать свои собственные классы (это всегда будет лучше, чем играть с необработанными указателями), либо вам запрещено использовать большинство, если не все функции C++, и в В этом случае, как указал Санджайя Р., вы программируете на C. Поэтому использование new можно рассматривать как нарушение ваших рекомендаций ... ^ _ ^ ... В любом случае, я рад, что я не в вашем положении .

paercebal 31.07.2010 18:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
4
4 792
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Обновлено: Думаю, я неправильно понял ваш вопрос. Я знаю, что в этом коде нет проблемы с постоянством.

Я делаю это из головы, но все должно быть правильно:

static int lastIndex = 0;
static char **registeredNames = new char*[numberOfNames];

void RegisterName(const * char const name)
{
    bool found = false;
    //loop to see if name already registered snipped
    for (int i = 0; i < lastIndex; i++)
    {
        if (strcmp(name, registeredNames[i] == 0))
        {
            found = true;
            break;
        }
    }

    if (!found)
    {
        registeredNames[lastIndex++] = name;
    }
}

при этом не будет компилироваться bool, найденный внутри for, а область видимости внутри for. вам нужно переместить bool found = false; до for.

Jorge Ferreira 18.09.2008 15:31
Ответ принят как подходящий

Вероятно, вам нужно будет использовать strcmp, чтобы узнать, сохранена ли уже строка:

for (int index=0; index<=lastIndex; index++)
{
  if (strcmp(registeredNames[index], name) == 0)
  {
    return; // Already registered
  }
}

Затем, если вам действительно нужно сохранить копию строки, вам нужно выделить буфер и скопировать символы.

char* nameCopy = malloc(length+1);
strcpy(nameCopy, name);
registeredNames[lastIndex++] = nameCopy;

Вы не упомянули, завершается ли ваш ввод NULL - в противном случае требуется дополнительная осторожность, и strcmp / strcpy не подойдет.

Работа с char * требует, чтобы вы работали с функциями C. В вашем случае вам действительно нужно скопировать строки. Чтобы помочь вам, у вас есть функция strndup. Тогда вам нужно будет написать что-то вроде:

void RegisterName(const char* name)
{
  // loop to see if name already registered snipped
  if (notFound)
  {
    registerNames[lastIndex++] = stdndup(name, MAX_STRING_LENGTH);
  }
}

Этот код предполагает, что ваш массив достаточно большой.

Конечно, лучше всего было бы правильно реализовать собственную строку, массив и список ... или убедить своего босса, что STL больше не является злом!

С помощью:

const char **registeredNames = new const char * [numberOfNames];

позволит вам назначить const * char const элементу массива.

Просто из любопытства, почему «работа требует, чтобы ни одна из самых удобных конструкций C++ не использовалась»?

Потому что я работаю в игровой компании, и код должен быть суперпортативным. Я не был здесь так долго, но, насколько я могу понять, STL и большинство других библиотек, не предоставляемых используемым нами набором инструментов, находятся «вне пределов»

xan 18.09.2008 15:34

Я не думаю, что есть какие-либо платформы, на которых STL больше не доступен, но по крайней мере я бы посоветовал вашему боссу, чтобы кто-нибудь из вашей компании сядет и напишет библиотеку строк / коллекций для всех вас. Возиться с таким дерьмом просто ... непродуктивно.

Maximilian 18.09.2008 15:41

Я скорее соглашусь с вами вздох. Придется ткнуть своего супервизора и получить указатели извинения за каламбур ...

xan 18.09.2008 15:43

Да, отказ от STL снизит продуктивность разработки на 50%. Получите разрешение на использование STL (и усиление интеллектуальных указателей!), Даже если вам нужно купить библиотеку STL для некоторых платформ. Жертвовать такой производительностью разработчика без тщательного анализа переносимости STL - дорого.

emk 18.09.2008 15:51

Игровыми компаниями обычно управляют люди, которые не имеют ни малейшего понятия или должны все изобретать здесь (я был программистом игр). STL означает «Библиотека шаблонов Стандарт». Это стандарт. И это портативно, особенно такие вещи, как STLPort (stlport.org/product.html).

Skizz 18.09.2008 16:46

Почему вы не можете использовать STL?

В любом случае, я бы посоветовал вам реализовать собственный простой строковый класс и шаблоны списков. Таким образом, вы можете использовать те же методы, что и обычно, и сохранить указатель и управление памятью только этими классами. Если бы вы имитировали STL, было бы еще лучше.

Потому что я работаю в игровой компании, и код должен быть суперпортативным. Я не был здесь так долго, но, насколько я могу понять, STL и большинство других библиотек, не предоставляемых используемым нами набором инструментов, находятся «вне пределов»

xan 18.09.2008 15:34

Привет, xan, я тоже написал код игры, и у меня не было проблем с запуском кода STL на PS2 или XBox. Я даже попробовал его на старом добром PsOne, и он сработал (хотя код немного раздулся).

Nils Pipenbrinck 18.09.2008 16:10

Не понимаю почему. Хорошая вещь в библиотеках шаблонов заключается в том, что вы платите только за то, что используете, поэтому добавление STLport и простое использование строк и списков добавит ровно столько, сколько вы сами написали эти функции.

Ferruccio 18.09.2008 20:55

Если переносимость является проблемой, вы можете проверить STLport.

Если вы действительно не можете использовать stl (и я сожалею, что это было правдой, когда я работал в игровой индустрии), то разве вы не можете создать свой собственный строковый класс? Самый простой из строковых классов будет выделять память при построении и назначении и обрабатывать удаление в деструкторе. Позже вы можете добавить дополнительные функции по мере необходимости. Полностью переносимый, очень простой в написании и модульном тестировании.

Я могу понять, почему вы не можете использовать STL - большинство из них ужасно раздувают ваш код. Однако есть реализации для программистов игр разработчиками игр - RDESTL - одна из таких библиотек.

Существуют законные причины, по которым можно избежать использования STL. При работе в фиксированных средах, где память или скорость важны, иногда трудно сказать, что происходит под капотом STL. Да, вы можете написать свои собственные распределители памяти, и да, скорость обычно не проблема, но есть различия между реализациями STL на разных платформах, и эти различия могут быть тонкими и потенциально ошибочными. Память, пожалуй, самая большая проблема, когда я думаю об ее использовании.

Память бесценна, и то, как мы ее используем, нужно строго контролировать. Если вы не пошли по этому пути, эта концепция может не иметь смысла, но это правда. Мы разрешаем использование STL в инструментах (вне игрового кода), но это запрещено внутри самой игры. Еще одна проблема, связанная с размером кода. Я немного не уверен, насколько STL может повлиять на размер исполняемого файла, но мы видели заметное увеличение размера кода при использовании STL. Даже если ваш исполняемый файл «всего» на 2M больше, это на 2M меньше оперативной памяти для чего-то еще для вашей игры.

STL, безусловно, хорош. Но им могут злоупотреблять программисты, которые не знают, что делают. Это не намеренно, но может преподнести неприятные сюрпризы, если вы не хотите их видеть (опять же, раздутие памяти и проблемы с производительностью).

Я уверен, что вы близки со своим решением.

for ( i = 0; i < lastIndex; i++ ) {
    if ( !strcmp(&registeredNames[i], name ) {
        break;    // name was found
    }
}
if ( i == lastIndex ) {
    // name was not found in the registeredNames list
    registeredNames[lastIndex++] = strdup(name);
}

Возможно, вы не захотите использовать strdup. Это просто пример того, как сохранить имя, указанное в вашем примере. Возможно, вы захотите убедиться, что вы либо сами не хотите выделять место для нового имени, либо использовать какую-либо другую конструкцию памяти, которая может быть уже доступна в вашем приложении.

И, пожалуйста, не пишите строковый класс. Я назвал строковые классы, возможно, худшим примером того, как не перепроектировать базовую конструкцию C в C++. Да, строковый класс может скрыть от вас множество интересных деталей, но его шаблоны использования памяти ужасны, и они плохо вписываются в среду консоли (например, ps3 или 360 и т. д.). Примерно 8 лет назад мы сделали то же самое. 200000+ выделений памяти, прежде чем мы перейдем в главное меню. Память была ужасно фрагментирована, и мы не могли заставить остальную часть игры уместиться в фиксированной среде. Мы закончили вырывать его.

Дизайн классов хорош для некоторых вещей, но это не одно из них. Это мнение, но оно основано на реальном опыте.

Нет ничего плохого в STL и ограниченных устройствах. STL использует распределители, которые могут быть определены пользователем. Создайте распределитель, который выделяет только фиксированный объем ОЗУ и не допускает фрагментации памяти в остальной части системы.

Skizz 18.09.2008 16:50

конечно, при условии, что вы можете предоставить надлежащий объем оперативной памяти. Со временем все это можно исправить, и так оно и есть. Дело в том, что вы должны понимать свои шаблоны распределения, чтобы быть уверенным, что у вас не закончится оперативная память. Большинство людей этого не понимают, и у них возникают проблемы.

Mark 18.09.2008 17:05

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

Mark 18.09.2008 17:11

Так чем вы его заменили? Если бы происходило более 200000 распределений, мне казалось, что это проблема системы, а не только класса, хотя плохо реализованный класс может быть неэффективным (см. Книги Скотта Мейерса по эффективному C++).

Skizz 18.09.2008 17:35

мы заменили его строками в стиле C фиксированного размера и стандартными вызовами строк C. Мы достаточно знали о размерах строк, которые нам нужны, поэтому просто зафиксировали их длину в таких вещах, как MAX_STRING_LEN.

Mark 18.09.2008 19:25

@Mark: Идея о том, чтобы приспособить ваш шаблон использования и распределение памяти к модели консоли (или мобильной консоли), очень актуальна. Моя команда работает точно так же: мы дорожим каждым байтом памяти, потому что он напрямую связан с тем, сколько мы можем сделать с остальной памятью ... вплоть до уровня регистров. Таким образом, объекты STL (а также boost, opencv и другие библиотеки) полностью запрещены. Дело не в том, что они плохо спроектированы, а в том, что незнание того, как они используют каждую часть памяти и когда / как они выделяют / копируют, не позволяет нам предсказать состояние памяти и оптимизировать нашу игру.

Erika Electra 22.05.2012 11:20

Если вас не беспокоят условности и вы просто хотите, чтобы работа была выполнена, используйте realloc. Я все время делаю такие вещи для списков, это выглядит примерно так:

T** list = 0;
unsigned int length = 0;

T* AddItem(T Item)
{
 list = realloc(list, sizeof(T)*(length+1));
 if (!list) return 0;
 list[length] = new T(Item);
 ++length;
 return list[length];
}

void CleanupList()
{
 for(unsigned int i = 0; i < length; ++i)
 {
  delete item[i];
 }
 free(list)
}

Вы можете сделать больше, например только перераспределяется каждый раз, когда размер списка удваивается, функции для удаления элементов из списка по индексу или путем проверки равенства, создание класса шаблона для обработки списков и т. д. (у меня есть один, который я написал много лет назад, и всегда использую себя ... но, к сожалению, Я на работе и не могу просто скопировать и вставить сюда). Честно говоря, это, вероятно, не превзойдет эквивалент STL, хотя может сравняться с его производительностью, если вы проделаете тонну работы или у вас будет особенно плохая реализация STL.

Досадно, что C++ не имеет оператора обновления / изменения размера для замены realloc, что было бы очень полезно.

Да, и извиняюсь, если мой код содержит ошибку, я просто вытащил ее из памяти.

Все предложенные подходы действительны, я хочу сказать, что если способ, которым это делает C#, является привлекательным, воспроизведите его, создайте свои собственные классы / интерфейсы для представления той же абстракции, то есть простого класса связанного списка с методами Contains и Add, используя предоставленный образец кода по другим ответам это должно быть относительно просто.

Одна из замечательных особенностей C++ заключается в том, что обычно вы можете заставить его выглядеть и действовать так, как вы хотите, если в другом языке есть отличная реализация чего-то, что вы обычно можете воспроизвести.

Константная корректность остается константной корректностью независимо от того, используете ли вы STL или нет. Я считаю, что вы ищете, чтобы зарегистрированные имена были const char **, чтобы назначение registeredNames[i] (которое является const char *) работало.

Более того, действительно ли вы этим хотите заниматься? Похоже, что сделать копию строки, вероятно, более уместно.

Более того, вам не следует думать о сохранении этого в списке, учитывая операцию, которую вы выполняете над ним, будет лучше.

Я использовал этот класс String в течение многих лет.

http://www.robertnz.net/string.htm

Он обеспечивает практически все функции Строка STL, но реализована как настоящий класс, а не как шаблон и не использует STL.

Это явный случай, когда вы сами решаете сами. И проделайте то же самое с векторным классом.

  • Сделайте это с тестовым программированием.
  • Будь проще.

Избегайте подсчета ссылок в строковом буфере, если вы работаете в среде MT.

Другие вопросы по теме