C ++ STL map: insert хранит нулевые указатели - PullRequest
1 голос
/ 11 июня 2011

У меня есть простой класс

    class symbol_entry
{
private:
    static unsigned long uid;

public:
    std::string name;
    std::string filename;
    unsigned int line_number;
    unsigned int column_number;
    symbol_entry* parent_symbol;
    std::map<const char*,symbol_entry*> child_symbols;
    unsigned long type_flags;

public:
    symbol_entry();
    symbol_entry(const char* name,
                 const char* filename,
                 int line_number,
                 int column_number,
                 symbol_entry* parent_symbol,
                 unsigned long type_flags);
    ~symbol_entry();

    symbol_entry* get_child(const char* name);
    bool put_child(symbol_entry* child);
};

. Вот реализация symbol_entry :: put_child;

bool symbol_entry::put_child(symbol_entry* child)
{   
    if(child_symbols[child->name.c_str()])
        return false;
    child_symbols.insert(std::make_pair(child->name.c_str(),child));
    return true;
}

всякий раз, когда я выполняю такой тест;

symbol_entry* tsym=new symbol_entry("test","$",0,0,0,0);
symbol_entry* tcsym=new symbol_entry("test_child","$",0,0,0,0);
tsym->put_child(tcsym);
std::cout<<tsym->child_symbols.begin()->first<<" => "<<tsym->child_symbols.begin()->second<<std::endl;

child_symbols.begin () -> second хранит нулевой указатель.Я не могу решить это и перепробовал много вариантов, включая const и ссылки, чтобы помочь.

Ответы [ 5 ]

5 голосов
/ 11 июня 2011

child_symbols[child->name.c_str()] всегда создает и возвращает новую запись карты (NULL), а затем child_symbols.insert(...) ничего не делает (поэтому значение на карте остается NULL). Правильный способ проверить наличие ключа на карте - использовать find:

if (child_symbols.find(...) != child_symbols.end()) // already exists
4 голосов
/ 11 июня 2011

Вы сравниваете указатели по значению.Вам нужно сравнить то, на что они указывают .Пример:

std::string s1 = "Hello World!";
std::string s2 = s1;
s1.c_str() != s2.c_str()

Именно поэтому использование C-строк определенно не считается целесообразным в программе на C ++ - std::string сравнивает по значению.

1 голос
/ 11 июня 2011

Это:

child_symbols.insert(std::make_pair(child->name.c_str(),child));

Не в порядке: вы сохраняете результат c_str (), который не является долговременным значением.Он дает вам указатель на строку C, которая действительна сразу после того, как вы ее вызвали, но недопустима для последующего хранения и чтения.Вы должны заставить свою карту использовать std :: string в качестве типа ключа.

1 голос
/ 11 июня 2011

child_symbols[child->name.c_str()] не делает то, что вы думаете: он вставляет объект по умолчанию, который в вашем случае является указателем symbol_entry каждый раз.Я могу ошибаться, но я думаю, что

if(child_symbols[child->name.c_str()])

всегда будет оцениваться как true, потому что std::map вставит запись для вас.

0 голосов
/ 11 июня 2011

Вставка ничего не сделает, если элемент уже существует на карте. Ваша проверка child_symbols[child->name.c_str()] создаст элемент в его состоянии по умолчанию, поэтому так и происходит.

Вы можете использовать find вместо этого, чтобы выполнить проверку, но insert уже имеет эту встроенную функцию:

bool symbol_entry::put_child(symbol_entry* child)
{
    return child_symbols.insert(std::make_pair(child->name,child)).second;
}

Редактировать: Кроме того, что сказал DeadMG - используйте std::string вместо const char*, чтобы исправить это

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...