5

私は過去に 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 リストなどを使用して常にこの状況を回避してきたことです。それを回避する必要がありました!

4

14 に答える 14

7

STL を回避できる正当な理由があります。メモリや速度が重視される固定環境で作業する場合、STL の内部で何が行われているのかを判断するのが難しい場合があります。はい、独自のメモリ アロケータを作成できます。速度は一般的に問題ではありませんが、プラットフォーム間の STL 実装には違いがあり、それらの違いは微妙で潜在的にバグがある可能性があります。メモリは、それを使用することを考えるとき、おそらく私の最大の関心事です。

記憶は貴重であり、その使用方法を厳密に制御する必要があります。あなたがこの道を進んでいない限り、この概念は意味をなさないかもしれませんが、それは本当です. ツール内 (ゲーム コード外) での STL の使用は許可されていますが、実際のゲーム内では禁止されています。もう 1 つの関連する問題は、コード サイズです。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以上のメモリ割り当て。メモリはひどく断片化されており、ゲームの残りの部分を固定環境に収めることができませんでした。私たちはそれを引き裂いてしまいました。

クラス設計はいくつかの点で優れていますが、これはその 1 つではありません。これは意見ですが、実際の経験に基づいています。

于 2008-09-18T12:17:23.727 に答える
6

文字列が既に保存されているかどうかを確認するには、おそらく 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 は適切ではありません。

于 2008-09-18T11:28:57.960 に答える
5

移植性が問題になる場合は、STLportを確認してください。

于 2008-09-18T11:46:39.510 に答える
3

なぜ STL を使用できないのですか?

とにかく、単純な文字列クラスと独自のリスト テンプレートを実装することをお勧めします。そうすれば、通常と同じ手法を使用して、ポインタとメモリ管理をそれらのクラスに限定することができます。STLを模倣すれば、さらに良いでしょう。

于 2008-09-18T11:29:27.803 に答える
2

本当に stl を使用できない場合 (私がゲーム業界にいたときはそうだったと信じていたことを後悔しています)、独自の文字列クラスを作成できないでしょうか? 文字列クラスの最も基本的なものは、構築と代入でメモリを割り当て、デストラクタで削除を処理します。必要に応じて、後でさらに機能を追加できます。完全に移植可能で、書き込みと単体テストが非常に簡単です。

于 2008-09-18T11:56:12.827 に答える
1

STLを使用できない理由は理解できます。ほとんどの場合、コードがひどく肥大化します。ただし、ゲームプログラマーによるゲームプログラマー向けの実装があります。RDESTLはそのようなライブラリの1つです。

于 2008-09-18T12:13:00.880 に答える
1

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はもはや悪ではないことを上司に納得させることです!

于 2008-09-18T11:29:23.263 に答える
1

使用:

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

const * char const配列の要素にa を割り当てることができます。

好奇心から、なぜ「最も便利な C++ 構造体を使用できないことが仕事で義務付けられている」のですか?

于 2008-09-18T11:29:27.540 に答える
1

編集:あなたの質問を誤解したと思います。私が認識しているこのコードには、一貫性の問題はありません。

私は頭からこれをやっていますが、それはほぼ正しいはずです:

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;
    }
}
于 2008-09-18T11:26:05.567 に答える
0

私はこの String クラスを何年も使用してきました。

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

STL 文字列の実質的にすべての機能を提供しますが、テンプレートではなく真のクラスとして実装され、STL を使用しません。

于 2008-09-18T23:08:27.843 に答える
0

これは、自分でロールバックできる明確なケースです。ベクトルクラスについても同じことを行います。

  • テスト優先プログラミングでそれを行います。
  • 複雑にしないでおく。

MT 環境の場合は、文字列バッファーの参照カウントを避けてください。

于 2008-09-19T17:29:33.520 に答える
0

慣習を気にせず、ただ仕事を終わらせたいだけなら、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)
}

できることは他にもあります。たとえば、リスト サイズが 2 倍になるたびにのみ再割り当てする、インデックスまたは等価性をチェックすることによってリストからアイテムを削除する関数、リストを処理するためのテンプレート クラスを作成するなどです。常に自分自身を使用してください...しかし、悲しいことに、私は仕事をしていて、ここにコピーアンドペーストすることはできません)。ただし、かなりの量の作業を行ったり、STL の実装が特に不十分な場合は、同等のパフォーマンスが得られる可能性がありますが、完全に正直に言うと、これはおそらく STL の同等のパフォーマンスよりも優れているとは言えません。

厄介なことに、C++ には、realloc を置き換える演算子 renew/resize がありません。これは非常に便利です。

ああ、私のコードにエラーが多発している場合は申し訳ありません。メモリから引き出しただけです。

于 2008-09-18T12:37:28.343 に答える
0

提案されたすべてのアプローチは有効です。私のポイントは、C# の方法が魅力的である場合は、それを複製し、独自のクラス/インターフェイスを作成して、同じ抽象化を提示することです。他の答えでは、これは比較的単純なはずです。

C++ の優れた点の 1 つは、通常、別の言語に優れた実装があり、通常はそれを再現できる場合に、外観と動作を思いどおりにできることです。

于 2008-09-18T13:18:05.670 に答える
0

const の正確性は、STL を使用するかどうかに関係なく、const の正確性のままです。あなたが探しているのは、 registeredNames を aにして、 ( a である)const char **への割り当てが機能するようにすることだと思います。registeredNames[i]const char *

さらに、これは本当にあなたがやりたいことですか?文字列のコピーを作成する方がおそらく適切なようです。

さらに、これに対して行っている操作を考えると、これをリストに格納することを考えるべきではありません。セットの方が良いでしょう。

于 2008-09-18T13:37:02.147 に答える