87

次のコードが機能しない理由を突き止めようとしています。キー タイプとして char* を使用することに問題があると想定していますが、解決方法や発生理由がわかりません。私が (HL2 SDK で) 使用する他の関数はすべて使用するchar*ため、使用std::stringすると多くの不必要な複雑さが生じます。

std::map<char*, int> g_PlayerNames;

int PlayerManager::CreateFakePlayer()
{
    FakePlayer *player = new FakePlayer();
    int index = g_FakePlayers.AddToTail(player);

    bool foundName = false;

    // Iterate through Player Names and find an Unused one
    for(std::map<char*,int>::iterator it = g_PlayerNames.begin(); it != g_PlayerNames.end(); ++it)
    {
        if(it->second == NAME_AVAILABLE)
        {
            // We found an Available Name. Mark as Unavailable and move it to the end of the list
            foundName = true;
            g_FakePlayers.Element(index)->name = it->first;

            g_PlayerNames.insert(std::pair<char*, int>(it->first, NAME_UNAVAILABLE));
            g_PlayerNames.erase(it); // Remove name since we added it to the end of the list

            break;
        }
    }

    // If we can't find a usable name, just user 'player'
    if(!foundName)
    {
        g_FakePlayers.Element(index)->name = "player";
    }

    g_FakePlayers.Element(index)->connectTime = time(NULL);
    g_FakePlayers.Element(index)->score = 0;

    return index;
}
4

9 に答える 9

151

マップに比較ファンクターを指定する必要があります。そうしないと、ポインターが指す null で終わる文字列ではなく、ポインターが比較されます。一般に、これは、マップ キーをポインターにしたい場合に当てはまります。

例えば:

struct cmp_str
{
   bool operator()(char const *a, char const *b) const
   {
      return std::strcmp(a, b) < 0;
   }
};

map<char *, int, cmp_str> BlahBlah;
于 2010-11-11T18:07:38.157 に答える
48

文字列ではなく、まったく同じポインターchar*でマップにアクセスすることが100%確実でない限り、使用できません。

例:

char *s1; // pointing to a string "hello" stored memory location #12
char *s2; // pointing to a string "hello" stored memory location #20

でマップにs1アクセスすると、 でアクセスする場合とは異なる場所が表示されますs2

于 2010-11-11T18:06:10.840 に答える
25

2 つの C スタイルの文字列は、内容が同じでもアドレスが異なる場合があります。そしてmap、内容ではなくポインターを比較します。

に変換するコストは、std::map<std::string, int>思ったほど高くないかもしれません。

const char*ただし、本当にマップ キーとして使用する必要がある場合は、次を試してください。

#include <functional>
#include <cstring>
struct StrCompare : public std::binary_function<const char*, const char*, bool> {
public:
    bool operator() (const char* str1, const char* str2) const
    { return std::strcmp(str1, str2) < 0; }
};

typedef std::map<const char*, int, StrCompare> NameMap;
NameMap g_PlayerNames;
于 2010-11-11T18:10:26.120 に答える
9

で動作させることができますが、マップがそれらをキーとして参照している間はこれらの文字列を変更してはならstd::map<const char*, int>ないため、非ポインターを使用してはなりません (キーにconstが追加されていることに注意してください)。const(マップはキーを作成することでキーを保護しますがconst、これはポインターを構成するだけであり、ポインターが指す文字列は構成しません。)

しかし、単に使用しないのはなぜstd::map<std::string, int>ですか? 頭を悩ませることなく、箱から出してすぐに使用できます。

于 2010-11-11T18:15:40.733 に答える
8

a の使用と文字列の使用を比較してchar *います。それらは同じではありません。

Achar *は char へのポインターです。最終的には、値が の有効なアドレスとして解釈される整数型ですchar

文字列は文字列です。

コンテナーは正しく機能しますが、キーが でchar *値がであるペアのコンテナーとして機能しintます。

于 2010-11-11T18:07:21.883 に答える
2

他の人が言うように、この場合はおそらく char* の代わりに std::string を使用する必要がありますが、それが本当に必要な場合は、ポインターをキーとして使用しても原則として問題はありません。

このコードが機能しないもう 1 つの理由は、マップで使用可能なエントリを見つけたら、同じキー (char*) を使用してマップに再挿入しようとするためだと思います。そのキーはマップに既に存在するため、挿入は失敗します。map::insert() の標準では、この動作が定義されています...キー値が存在する場合、挿入は失敗し、マップされた値は変更されません。その後、とにかく削除されます。最初に削除してから再挿入する必要があります。

char* を std::string に変更しても、この問題は残ります。

私はこのスレッドがかなり古いことを知っており、あなたは今までにすべて修正しましたが、誰もこの点を指摘していないので、将来の視聴者のために私は答えています.

于 2012-04-16T13:47:10.647 に答える
-5

<比較 ( 、>==) と割り当てをサポートしている限り、どのキー タイプを使用しても問題はありません。

言及する必要がある 1 つのポイント -テンプレートクラスを使用していることを考慮してください。結果として、コンパイラは と の 2 つの異なるインスタンス化を生成char*しますint*。一方、両方の実際のコードは実質的に同じです。

したがってvoid*、キータイプとして a を使用し、必要に応じてキャストすることを検討します。これは私の意見。

于 2010-11-11T18:10:33.040 に答える