4

const char ポインターの束を std::set コンテナーに保持したい [1]。std::set テンプレートにはコンパレータ ファンクターが必要であり、標準 C++ ライブラリは std::less を提供しますが、その実装は 2 つのキーを直接比較することに基づいており、ポインターの標準ではありません。

ポインターを整数にキャストして比較することで、独自のファンクターを定義して operator() を実装できることはわかっていますが、よりクリーンで「標準的な」方法はありますか?

std::strings の作成を提案しないでください - 時間とスペースの無駄です。文字列は静的であるため、アドレスに基づいて等しいかどうかを比較できます。

1: ポインターは静的文字列へのポインターであるため、その寿命に問題はありません。消えません。

4

8 に答える 8

8

それらを s でラップしたくない場合はstd::string、ファンクター クラスを定義できます。

struct ConstCharStarComparator
{
  bool operator()(const char *s1, const char *s2) const
  {
    return strcmp(s1, s2) < 0;
  }
};

typedef std::set<const char *, ConstCharStarComparator> stringset_t;
stringset_t myStringSet;
于 2008-10-24T21:34:57.680 に答える
3

デフォルトの順序である less<> を使用してください。標準では、異なるオブジェクトへのポインタに対しても less が機能することが保証されています。

「より大きな、より少ない、より大きな等号、およびより少ない等号のテンプレートの場合、組み込み演算子 <、>、<=、>= がそうでない場合でも、任意のポインタ型の特殊化により合計順序が生成されます。」

保証はあなたのようなもののために正確にありますset<const char*>.

于 2008-10-25T12:57:22.243 に答える
3

「最適化された方法」

「時期尚早の最適化はすべての悪の根源」を無視する場合、標準的な方法はコンパレーターを追加することです。これは簡単に記述できます。

struct MyCharComparator
{
   bool operator()(const char * A, const char * B) const
   {
      return (strcmp(A, B) < 0) ;
   }
} ;

で使用するには:

std::set<const char *, MyCharComparator>

標準的な方法

使う:

std::set<std::string>

内部に static const char * を入れても機能します (const char * とは異なり、std::string はその内容によって比較できるため)。

もちろん、データを抽出する必要がある場合は、std::string.c_str() を介してデータを抽出する必要があります。一方、 ですが、セットなので、「AAA」の値「AAA」を抽出するのではなく、「AAA」がセットに含まれているかどうかだけを知りたいと思います。

注:「std :: stringの作成を提案しないでください」について読みましたが、「標準」の方法を尋ねました...

「絶対にしない」方法

回答後に次のコメントを書き留めました。

std::strings の作成を提案しないでください - 時間とスペースの無駄です。文字列は静的であるため、アドレスに基づいて (不) 等号を比較できます。

これは C のにおいがします (非推奨の "static" キーワードの使用、std::string バッシングに使用される時期尚早の最適化、およびそれらのアドレスによる文字列比較)。

とにかく、文字列をアドレスで比較したくありません。あなたが望む最後のことは、次のものを含むセットを持つことだと思うからです:

{ "AAA", "AAA", "AAA" }

もちろん、文字列を格納するために同じグローバル変数のみを使用する場合、これは別の話です。

この場合、次のことをお勧めします。

std::set<const char *>

もちろん、内容が同じで変数・アドレスが異なる文字列同士を比較してもうまくいきません。

もちろん、静的な const char *文字列がヘッダーで定義されている場合、それらの文字列では機能しません。

しかし、これは別の話です。

于 2008-10-24T21:32:42.223 に答える
0

との字句比較を行う方法を示す多くの解決策を他の人がすでに投稿しているconst char*ので、私は気にしません。

std::strings の作成を提案しないでください - 時間とスペースの無駄です。

std::string時間とスペースの無駄なら、時間とスペースstd::setの無駄かもしれません。a の各要素はstd::set、フリー ストアとは別に割り当てられます。std::setプログラムがセットをどのように使用するかによって、これはの O(log n) ルックアップがパフォーマンスを向上させる以上にパフォーマンスを低下させる可能性があります。std::vectorセットの意図された有効期間に応じて、 sorted 、またはコンパイル時にソートされる静的に割り当てられた配列など、別のデータ構造を使用すると、より良い結果が得られる場合があります。

標準 C++ ライブラリは std::less を提供しますが、その実装は 2 つのキーを直接比較することに基づいており、ポインターの標準ではありません。

文字列は静的であるため、アドレスに基づいて等しいかどうかを比較できます。

それは、ポインターが何を指しているかによって異なります。すべてのキーが同じ配列から割り当てられている場合、operator<ポインターを比較するために使用することは未定義の動作ではありません。

個別の静的文字列を含む配列の例:

static const char keys[] = "apple\0banana\0cantaloupe";

を作成し、std::set<const char*>その配列を指すポインターで埋めると、それらの順序は明確に定義されます。

ただし、文字列がすべて別個の文字列リテラルである場合、それらのアドレスを比較すると、未定義の動作が発生する可能性が高くなります。機能するかどうかは、コンパイラ/リンカーの実装、使用方法、および期待に依存します。

コンパイラ/リンカーが文字列プーリングをサポートし、それを有効にしている場合、重複する文字列リテラルは同じアドレスを持つ必要がありますが、すべての場合に保証されていますか? 正しい機能のためにリンカーの最適化に頼るのは安全ですか?

1 つの翻訳単位でのみ文字列リテラルを使用する場合、セットの順序は文字列が最初に使用された順序に基づく場合がありますが、別の翻訳単位を変更して同じ文字列リテラルのいずれかを使用すると、セットの順序が変わる場合があります。

独自のファンクターを定義し、ポインターを整数にキャストして比較することで operator() を実装できることを知っています

ポインターをキャストしuintptr_tても、ポインター比較を使用するよりもメリットがないように思われます。結果はどちらの方法でも同じです: 実装固有です。

于 2008-10-25T07:33:55.490 に答える
0

「束」の大きさに応じて、対応するstd::stringの束をセットに格納する傾向があります。そうすれば、余分なグルー コードを記述する必要がなくなります。

于 2008-10-24T21:30:50.387 に答える
0

セットに含まれている必要がありますconst char*か?

すぐに頭に浮かぶのは、std::string代わりに文字列を に格納し、それらを に入れることstd::setです。const char*これにより、問題なく比較が可能になり、簡単な関数呼び出しでいつでも raw を取得できます。

const char* data = theString.c_str();
于 2008-10-24T21:33:12.440 に答える
0

コンパレーターを使用するか、ラッパー型を使用してセットに含めてください。(注:ラッパーでもあります.... std::string

const char* a("a");
const char* b("b");

struct CWrap {
    const char* p;
    bool operator<(const CWrap& other) const{
        return strcmp( p, other.p ) < 0;
    }
    CWrap( const char* p ): p(p){}
};

std::set<CWrap> myset;
myset.insert(a);
myset.insert(b);
于 2008-10-24T21:49:47.540 に答える
-1

おそらく、パフォーマンス上の理由から std::string を使用したくないでしょう。

私は MSVC と gcc を実行していますが、どちらもこれを気にしないようです:

bool foo = "blah" < "grar";

編集:ただし、この場合の動作は指定されていません。コメントを見る...

彼らはまた文句を言いませんstd::set<const char*>

不平を言うコンパイラを使用している場合は、ポインターを s にキャストする提案されたファンクターを使用することになるでしょうint

編集: ねえ、私は投票で落とされました...彼の質問に最も直接的に答えた数少ない人の 1 人であるにもかかわらず。私は Stack Overflow を初めて使用します。これが発生した場合に身を守る方法はありますか? そうは言っても、ここで試してみます:

問題は解決策を探すことではありませんstd::string。セットに in を入力するたびにstd::string、文字列全体をコピーする必要があります (とにかく C++0x が標準になるまで)。また、セット検索を行うたびに、複数の文字列比較を行う必要があります。

ただし、ポインターをセットに格納すると、文字列のコピーは発生せず (ポインターをコピーするだけです)、すべての比較はアドレスの単純な整数比較であり、文字列の比較ではありません。

質問は、文字列へのポインターを保存することは問題ないと述べましたが、このステートメントがエラーであるとすぐにみなすべき理由はわかりません。自分が何をしているのかわかっている場合は、const char*over eitherstd::stringまたは を呼び出すカスタム比較を使用すると、パフォーマンスが大幅に向上しますstrcmp。はい、安全性が低く、エラーが発生しやすくなりますが、これらはパフォーマンスの一般的なトレードオフです。質問にはアプリケーションが記載されていないため、彼はすでに長所と短所を考慮し、パフォーマンスを優先することに決めたと想定する必要があると思います.

于 2008-10-24T21:42:45.090 に答える