C ++ строки без <string>и STL - PullRequest
       24

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

4 голосов
/ 18 сентября 2008

В прошлом я не очень часто использовал C ++, а в последнее время много работаю с C #, и я действительно изо всех сил пытаюсь вернуться к основам C ++ снова. Это особенно непросто, поскольку в рабочих заданиях нельзя использовать ни одну из наиболее удобных конструкций C ++, поэтому все строки должны быть символами *, и для списков 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 и т. Д., Поэтому я никогда пришлось обойти это!

Прошу прощения за публикацию такого тривиального вопроса, и любая помощь будет принята с благодарностью!

Приветствия

1018 * Xan *

Ответы [ 14 ]

6 голосов
/ 18 сентября 2008

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

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 ++. Да, класс string может скрыть от вас множество изящных подробностей, но его шаблоны использования памяти ужасны, и они плохо вписываются в консольную среду (например, ps3 или 360 и т. Д.). Около 8 лет назад мы сделали то же самое. 200000+ выделений памяти, прежде чем мы попадем в главное меню. Память была ужасно фрагментирована, и мы не смогли заставить остальную часть игры вписаться в фиксированную среду. Мы закончили с этим.

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

5 голосов
/ 18 сентября 2008

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

5 голосов
/ 18 сентября 2008

Вам, вероятно, потребуется использовать 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 не подойдет.

3 голосов
/ 18 сентября 2008

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

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

2 голосов
/ 18 сентября 2008

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

1 голос
/ 18 сентября 2008

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

1 голос
/ 18 сентября 2008

Использование:

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

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

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

1 голос
/ 18 сентября 2008

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

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

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

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

1 голос
/ 18 сентября 2008

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

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

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;
    }
}
0 голосов
/ 19 сентября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...