Я не очень много использовал 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 и т. д., Поэтому я никогда не пришлось это обойти!
Кстати, в объявлении RegisterName должно быть «const char * const name», а не «const * char const name».
Так что вы на самом деле занимаетесь программированием на C?
Либо вам запрещено по какой-то странной причине не использовать STL, и тогда вы должны писать свои собственные классы (это всегда будет лучше, чем играть с необработанными указателями), либо вам запрещено использовать большинство, если не все функции C++, и в В этом случае, как указал Санджайя Р., вы программируете на C. Поэтому использование new можно рассматривать как нарушение ваших рекомендаций ... ^ _ ^ ... В любом случае, я рад, что я не в вашем положении .





Обновлено: Думаю, я неправильно понял ваш вопрос. Я знаю, что в этом коде нет проблемы с постоянством.
Я делаю это из головы, но все должно быть правильно:
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.
Вероятно, вам нужно будет использовать 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 и большинство других библиотек, не предоставляемых используемым нами набором инструментов, находятся «вне пределов»
Я не думаю, что есть какие-либо платформы, на которых STL больше не доступен, но по крайней мере я бы посоветовал вашему боссу, чтобы кто-нибудь из вашей компании сядет и напишет библиотеку строк / коллекций для всех вас. Возиться с таким дерьмом просто ... непродуктивно.
Я скорее соглашусь с вами вздох. Придется ткнуть своего супервизора и получить указатели извинения за каламбур ...
Да, отказ от STL снизит продуктивность разработки на 50%. Получите разрешение на использование STL (и усиление интеллектуальных указателей!), Даже если вам нужно купить библиотеку STL для некоторых платформ. Жертвовать такой производительностью разработчика без тщательного анализа переносимости STL - дорого.
Игровыми компаниями обычно управляют люди, которые не имеют ни малейшего понятия или должны все изобретать здесь (я был программистом игр). STL означает «Библиотека шаблонов Стандарт». Это стандарт. И это портативно, особенно такие вещи, как STLPort (stlport.org/product.html).
Почему вы не можете использовать STL?
В любом случае, я бы посоветовал вам реализовать собственный простой строковый класс и шаблоны списков. Таким образом, вы можете использовать те же методы, что и обычно, и сохранить указатель и управление памятью только этими классами. Если бы вы имитировали STL, было бы еще лучше.
Потому что я работаю в игровой компании, и код должен быть суперпортативным. Я не был здесь так долго, но, насколько я могу понять, STL и большинство других библиотек, не предоставляемых используемым нами набором инструментов, находятся «вне пределов»
Привет, xan, я тоже написал код игры, и у меня не было проблем с запуском кода STL на PS2 или XBox. Я даже попробовал его на старом добром PsOne, и он сработал (хотя код немного раздулся).
Не понимаю почему. Хорошая вещь в библиотеках шаблонов заключается в том, что вы платите только за то, что используете, поэтому добавление STLport и простое использование строк и списков добавит ровно столько, сколько вы сами написали эти функции.
Если переносимость является проблемой, вы можете проверить STLport.
Если вы действительно не можете использовать stl (и я сожалею, что это было правдой, когда я работал в игровой индустрии), то разве вы не можете создать свой собственный строковый класс? Самый простой из строковых классов будет выделять память при построении и назначении и обрабатывать удаление в деструкторе. Позже вы можете добавить дополнительные функции по мере необходимости. Полностью переносимый, очень простой в написании и модульном тестировании.
Я могу понять, почему вы не можете использовать STL - большинство из них ужасно раздувают ваш код. Однако есть реализации для программистов игр разработчиками игр - RDESTL - одна из таких библиотек.
Существуют законные причины, по которым можно избежать использования STL. При работе в фиксированных средах, где память или скорость важны, иногда трудно сказать, что происходит под капотом STL. Да, вы можете написать свои собственные распределители памяти, и да, скорость обычно не проблема, но есть различия между реализациями STL на разных платформах, и эти различия могут быть тонкими и потенциально ошибочными. Память, пожалуй, самая большая проблема, когда я думаю об ее использовании.
Память бесценна, и то, как мы ее используем, нужно строго контролировать. Если вы не пошли по этому пути, эта концепция может не иметь смысла, но это правда. Мы разрешаем использование STL в инструментах (вне игрового кода), но это запрещено внутри самой игры. Еще одна проблема, связанная с размером кода. Я немного не уверен, насколько STL может повлиять на размер исполняемого файла, но мы видели заметное увеличение размера кода при использовании STL. Даже если ваш исполняемый файл «всего» на 2M больше, это на 2M меньше оперативной памяти для чего-то еще для вашей игры.
STL, безусловно, хорош. Но им могут злоупотреблять программисты, которые не знают, что делают. Это не намеренно, но может преподнести неприятные сюрпризы, если вы не хотите их видеть (опять же, раздутие памяти и проблемы с производительностью).
Я уверен, что вы близки со своим решением.
for ( i = 0; i < lastIndex; i++ ) {
if ( !strcmp(®isteredNames[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 использует распределители, которые могут быть определены пользователем. Создайте распределитель, который выделяет только фиксированный объем ОЗУ и не допускает фрагментации памяти в остальной части системы.
конечно, при условии, что вы можете предоставить надлежащий объем оперативной памяти. Со временем все это можно исправить, и так оно и есть. Дело в том, что вы должны понимать свои шаблоны распределения, чтобы быть уверенным, что у вас не закончится оперативная память. Большинство людей этого не понимают, и у них возникают проблемы.
И вы все равно можете столкнуться с фрагментацией вашей личной кучи, которую вы создали и из которой выделяете. Создание распределителя не решает эту проблему, а только локализует ее.
Так чем вы его заменили? Если бы происходило более 200000 распределений, мне казалось, что это проблема системы, а не только класса, хотя плохо реализованный класс может быть неэффективным (см. Книги Скотта Мейерса по эффективному C++).
мы заменили его строками в стиле C фиксированного размера и стандартными вызовами строк C. Мы достаточно знали о размерах строк, которые нам нужны, поэтому просто зафиксировали их длину в таких вещах, как MAX_STRING_LEN.
@Mark: Идея о том, чтобы приспособить ваш шаблон использования и распределение памяти к модели консоли (или мобильной консоли), очень актуальна. Моя команда работает точно так же: мы дорожим каждым байтом памяти, потому что он напрямую связан с тем, сколько мы можем сделать с остальной памятью ... вплоть до уровня регистров. Таким образом, объекты STL (а также boost, opencv и другие библиотеки) полностью запрещены. Дело не в том, что они плохо спроектированы, а в том, что незнание того, как они используют каждую часть памяти и когда / как они выделяют / копируют, не позволяет нам предсказать состояние памяти и оптимизировать нашу игру.
Если вас не беспокоят условности и вы просто хотите, чтобы работа была выполнена, используйте 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.
Чем не работает?