2013-07-06 1 views
0

unordered_map을 사용하여 char * 키를 정수 값으로 해시하려고했습니다. 커스텀 Functor를 해시하고 char *를 비교 한 후, 정렬되지 않은 맵이 작동하는 것처럼 보였습니다. 그러나 결국 해시가 잘못된 결과를 반환하는 것으로 나타났습니다. 오류를 재현 할 테스트 프로젝트를 만들었습니다. 아래의 코드는 char * 키와 커스텀 펑터를 사용하여 unordered_map을 생성합니다. 그런 다음 1000x 사이클을 실행하고 발생한 모든 해시 오류를 기록합니다. 내 펑터에 문제가 있거나 문제가 unordered_map 내에있는 경우 궁금합니다. 어떤 도움을 주시면 감사하겠습니다. 감사!C++ unordered_map with char * key 예기치 않은 동작이 발생합니다.

#include <cstdlib> 
#include <stdio.h> 
#include <string.h> 
#include <time.h> 
#include <tr1/unordered_map> 

using namespace std; 

//These varaibles are just used for printing the status. 
static const char* c1; 
static const char* c2; 
static int cmpRet; 
static int cmpVal; 
static const char* hashChar; 
static size_t hashVal; 

// Character compare functor. 
struct CmpChar { 

    bool operator()(const char* s1, const char* s2) const { 
    c1 = s1; 
    c2 = s2; 
    cmpVal = strcmp(s1, s2); 
    cmpRet = (cmpVal == 0); 
    return cmpRet; 
    } 
}; 

// Hash functor. 
struct HashChar { 

    size_t operator()(const char* str) const { 
    hashChar = str; 
    size_t hash = 0; 
    int c; 

    while (c = *str++) 
     hash = c + (hash << 6) + (hash << 16) - hash; 

    hashVal = hash; 
    return hash; 
    } 
}; 

void printStatus() { 
    printf("'%s' was hashed to: '%lu'\n", hashChar, hashVal); 
    printf("strcmp('%s','%s')='%d' and KeyEqual='%d'\n", c1, c2, cmpVal, cmpRet); 
} 

int main(int argc, char** argv) { 

    // Create the unordered map. 
    tr1::unordered_map<const char*, int, HashChar, CmpChar > hash_map; 
    hash_map["apple"] = 1; 
    hash_map["banana"] = 2; 
    hash_map["orange"] = 3; 

    // Grab the inital hash value of 'apple' to see what it hashes to. 
    char buffer[256]; 
    bzero(buffer, sizeof (buffer)); 
    strcpy(buffer, "apple"); 
    if (hash_map[buffer] == 1) { 
    printf("First hash: '%s'=1\n", buffer); 
    } 
    printStatus(); 

    // Create a random character 
    srand((unsigned int) time(NULL)); 
    char randomChar = (rand() % 26 + 'a'); 

    // Use the hash 1000x times to see if it works properly. 
    for (int i = 0; i < 1000; i++) { 

    // Fill the buffer with 'apple' 
    bzero(buffer, sizeof (buffer)); 
    strcpy(buffer, "apple"); 

    // Try to get the value for 'apple' and report an error if it equals zero. 
    if (hash_map[buffer] == 0) { 
     printf("\n****Error: '%s'=0 ****\n", buffer); 
     printStatus(); 
    } 

    // Fill the buffer with a random string. 
    bzero(buffer, sizeof (buffer)); 
    buffer[0] = randomChar; 
    buffer[1] = '\0'; 

    // Hash the random string. 
    // ** Taking this line out removes the error. However, based on the functors 
    // it should be acceptable to reuse a buffer with different content. 
    hash_map[buffer]; 

    // Update the random character. 
    randomChar = (rand() % 26 + 'a'); 
    } 

    printf("done!\n"); 

    return EXIT_SUCCESS; 
} 
+1

포인터가 문자열이 아닙니다 ... – Pubby

+0

왜 char *가 아닌 문자열입니까? 또한이 태그가 C++ 11이기 때문에 std :: hash를 제안하려고합니다. Borgleader

+0

죄송합니다. String을 사용했는데 완벽하게 작동합니다. char *를 사용하고 싶습니다. 나머지 코드는 char *를 모두 사용했기 때문에 사용하고 싶습니다. 지금 당장 나는 왜 unordered_map이 char *와 작동하지 않는지 궁금해합니다. 코드가 올바른 것 같습니다 ... – HobbyDos

답변

2

char *를 사용할 수 있으므로 컨테이너에서 char *를 사용할 때는주의해야합니다.

unordered_map의 연산자 []를 사용하면 맵에서 키로 사용되는 것이 원하는 문자열이 아닙니다.

operator []는 키를지도에 삽입하고 기본 생성자 (see the reference)를 호출하여 복사합니다.이 경우 단순히 buffer [0]을 복사합니다.

그런 다음 CmpChar 메서드는 이상한 동작을합니다. 키에서 읽는 다음 바이트는 아무 것도 될 수 있습니다.

문자열 개체를 사용하면 이러한 문제가 발생하지 않습니다.

+0

고마워, [] 연산자가 실제로 해시에 새 값을 삽입한다는 사실로 인해 혼란이 올 것으로 생각됩니다. 대신 .find() 메서드를 사용하려고한다고 가정합니다. – HobbyDos