std ::使用char *類型設置查找行為

[英]std::set find behavior with char * type

I have below code line:


const char *values[] = { "I", "We", "You", "We"};
std::set<const char*> setValues;

for( int i = 0; i < 3; i++ ) {

    const char *val = values[i];
    std::set<const char*>::iterator it = setValues.find( val );

    if( it == setValues.end() ) {
        setValues.insert( val );
    else {
        cout << "Existing value" << endl;

With this I am trying to insert non-repeated values in a set, but somehow code is not hitting to print for existing element and duplicate value is getting inserted.


What is wrong here?


3 个解决方案



You should define less predicate for const char* and pass into the set template to make the set object works correctly with pointers:

您應該為const char *定義較少的謂詞,並傳入set模板以使set對象與指針一起正常工作:

  struct cstrless {
    bool operator()(const char* a, const char* b) {
      return strcmp(a, b) < 0;
  std::set<const char*, cstrless> setValues;



The std::set<T>::find uses a default operator < of the type T. Your type is const char*. This is a pointer to an address in memory so the find method just compares address in memory of given string to addresses in memory of all strings from set. These addresses are different for each string (unless compiler optimizes it out).

std :: set :: find使用類型為T的默認運算符。您的類型是const char *。這是一個指向內存中地址的指針,因此find方法只是將給定字符串的內存中的地址與set中所有字符串的內存中的地址進行比較。每個字符串的這些地址都不同(除非編譯器優化它)。

You need to tell std::set how to compare strings correctly. I can see that AnatolyS already wrote how to do it in his answer.

你需要告訴std :: set如何正確地比較字符串。我可以看到AnatolyS已經在他的回答中寫了如何做到這一點。



Unless you use a custom comparison function object, std::set uses operator<(const key_type&,key_type&) by default. Two pointers are equal if, and only if they point to the same object.

除非您使用自定義比較函數對象,否則std :: set默認使用operator <(const key_type&,key_type&)。如果且僅當它們指向同一個對象時,兩個指針是相等的。

Here is an example of three objects:


char a[] = "apple";
char b[] = "apple";
const char (&c)[6] = "apple"

First two are arrays, the third is an lvalue reference that is bound to a string literal object that is also an array. Being separate objects, their address is of course also different. So, if you were to write:


bool is_in_map = setValues.find("apple") != setValues.end();

The value of is_in_map would be false, because the set contains only the address of the string in a, and not the address of the string in the literal - even though the content of the strings are same.

is_in_map的值將為false,因為該集合僅包含a中字符串的地址,而不包含字面中字符串的地址 - 即使字符串的內容相同。

Solution: Don't use operator< to compare pointers to c strings. Use std::strcmp instead. With std::set, this means using a custom comparison object. However, you aren't done with caveats yet. You must still make sure that the strings stay in memory as long as they are pointed to by the keys in the set. For example, this would be a mistake:

解決方案:不要使用operator <來比較指向c字符串的指針。請改用std :: strcmp。使用std set,這意味着使用自定義比較對象。但是,你還沒有完成任何警告。只要字符串中的鍵指向它們,您仍必須確保字符串保留在內存中。例如,這將是一個錯誤:< p>

char a[] = "apple";
return setValues; // oops, we returned setValues outside of the scope
                  // but it contains a pointer to the string that
                  // is no longer valid outside of this scope

Solution: Take care of scope, or just use std::string.

解決方案:注意范圍,或者只使用std :: string。

(This answer plagiarises my own answer about std::map here)

(這個答案抄襲了我自己關於std :: map的答案)



粤ICP备14056181号  © 2014-2020