我过去不太使用 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);
}

我意识到这是行不通的。我知道传递的变量(const 指针和 const 字符串)的 const 性质使其相当困难,但我的基本问题是我过去总是通过使用 STL 列表等来避免这种情况。所以我从来不需要解决这个问题!

有帮助吗?

解决方案

您可能需要使用 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 不适合。

其他提示

避免 STL 是有正当理由的。当在内存或速度很重要的固定环境中工作时,有时很难用 STL 来判断底层发生了什么。是的,您可以编写自己的内存分配器,是的,速度通常不是问题,但是跨平台的 STL 实现之间存在差异,并且这些差异可能很微妙并且可能存在错误。在考虑使用内存时,内存可能是我最关心的问题。

内存是宝贵的,我们如何使用它需要严格控制。除非你一直走这条路,否则这个概念可能没有意义,但它是事实。我们确实允许在工具中使用 STL(在游戏代码之外),但在实际游戏中是禁止的。另一个相关问题是代码大小。我有点不确定 STL 对可执行文件大小的影响有多大,但我们发现使用 STL 时代码大小显着增加。即使您的可执行文件“仅”大 2M,对于游戏的其他内容来说,RAM 也会少 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?

无论如何,我建议您实现一个简单的字符串类并列出您自己的模板。这样您就可以使用与通常相同的技术,并将指针和内存管理限制在这些类中。如果能模仿STL那就更好了。

如果你真的不能使用 stl(我很遗憾在我从事游戏行业时相信这是真的)那么你不能创建自己的字符串类吗?最基本的字符串类将在构造和赋值时分配内存,并在析构函数中处理删除。稍后您可以根据需要添加更多功能。完全可移植,并且非常容易编写和单元测试。

使用 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 不再是邪恶的!

编辑:我想我误解了你的问题。据我所知,这段代码不存在常量问题。

我是从我的头脑中这样做的,但它应该是正确的:

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;
    }
}

我可以理解为什么你不能使用 STL - 大多数代码都会使你的代码变得非常膨胀。然而,游戏程序员有为游戏程序员提供的实现 - RDESTL 就是这样一个图书馆。

使用:

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

将允许您分配一个 const * char const 到数组的一个元素。

只是出于好奇,为什么“工作要求不能使用任何最方便的 C++ 结构”?

所有建议的方法都是有效的,我的观点是,如果 C# 的做法很有吸引力,可以复制它,创建您自己的类/接口来呈现相同的抽象,即一个带有方法 Contains 和 Add 的简单链表类,使用其他答案提供的示例代码,这应该相对简单。

C++ 的一个伟大之处在于,通常您可以使其外观和行为按照您想要的方式进行,如果另一种语言有很好的实现,您通常可以复制它。

我已经使用这个 String 类很多年了。

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

它实际上提供了STL字符串的所有功能,但被实现为真正的类,而不是模板,并且不使用STL。

这是一个明显的例子,你可以自己动手。对向量类执行相同的操作。

  • 通过测试优先编程来做到这一点。
  • 把事情简单化。

如果您处于 MT 环境中,请避免对字符串缓冲区进行引用计数。

如果您不担心约定而只想完成工作,请使用 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++ 没有运算符 renew/resize 来替代 realloc,这将非常有用。

哦,如果我的代码出错了,我很抱歉,我只是从内存中把它拉出来。

不管你是否使用STL,const正确性仍然是const正确性。我相信您正在寻找的是使 RegisteredNames 成为 const char ** 以便分配给 registeredNames[i] (这是一个 const char *)有效。

而且,这真的是你想做的吗?看来制作字符串的副本可能更合适。

此外,考虑到您正在对它执行的操作,您不应该考虑将其存储在列表中,一组会更好。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top