std ::使用char *类型设置查找行为

时间:2016-07-29 10:00:16

标签: c++ c++11 visual-c++ stdset

我有以下代码行:

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

有了这个,我试图在set中插入非重复值,但不知何故代码没有打印现有元素的打印,并且插入了重复值。

这里有什么问题?

3 个答案:

答案 0 :(得分:3)

你应该为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;

答案 1 :(得分:3)

std::set<T>::find使用<类型的默认运算符T。 您的类型为const char*。这是指向内存中地址的指针,因此find方法只是将给定字符串的内存中的地址与来自set的所有字符串的内存中的地址进行比较。这些地址对于每个字符串都是不同的(除非编译器对其进行优化)。

您需要告诉std::set如何正确比较字符串。我可以看到AnatolyS已经在他的回答中写了如何做到这一点。

答案 2 :(得分:0)

除非您使用自定义比较功能对象,否则std::set默认使用operator<(const key_type&,key_type&)。如果且仅当它们指向同一个对象时,两个指针是相等的。

以下是三个对象的示例:

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

前两个是数组,第三个是左值引用,它绑定到也是数组的字符串文字对象。作为独立的对象,他们的地址当然也不同。所以,如果你要写:

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

is_in_map的值为false,因为该集合仅包含a中字符串的地址,而不包含字面值中字符串的地址 - 即使字符串的内容相同。

解决方案:不要使用operator<来比较指向c字符串的指针。请改用std::strcmp。使用std::set,这意味着使用自定义比较对象。但是,你还没有做过警告。只要字符串中的键指向它们,您仍必须确保字符串保留在内存中。例如,这将是一个错误:

char a[] = "apple";
setValues.insert(a);
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

解决方案:注意范围,或只使用std::string

(这个答案抄袭了我自己关于std::map here的答案)