2009-05-04 2 views
3

Я пытаюсь определить, содержится ли объект в пределах std::set. Согласно msdn (и другим источникам) функция set :: find должна возвращать end(), если она не находит элемент, который вы попросили.Определение того, находится ли объект в std :: set

Однако, когда я реализую код, как показано ниже, set::find возвращает ненужный (0xbaadf00d).

set<Cell*> cellSet; 

Cell* cell = new Cell();  

if (cellSet.find(cell) == cellSet.end()) 
{ 
    ... 
} 

Я использую это правильно? Я работаю в Visual C++ 2005.

ответ

10

Вашего код, как отвечал всегда будет выполнять код в if и 0xbaadf00dявляется об осуществлении в «один-пришедшем к концу» маркер.

+0

Да, видимо, это был, по-видимому, крушение из какого-то другого места, потому что после перемещения какого-то материала вокруг, кажется, теперь все нормально. –

+2

Тот факт, что он произносимый и почти значимый, предполагает преднамеренную плохую ценность. По этой причине 0xdeadbeef был популярен как каноническое плохое или неинициализированное значение. –

+1

Вы не имеете в виду, что код как отправленный должен * всегда * выполнять код внутри if? cellSet пуст (никакие вставки не были выполнены в опубликованном коде), и ячейка является новой (возможно, она не может быть в cellSet, даже если была выполнена вставка), поэтому cellSet.find (cell) должен * всегда * возвращать cellSet.end(). Просто пытаюсь быть ясным. – Naaff

1

Имеет ли значение callSet.end() значение 0xbaadf00d?

EDIT

Я побежал этот пример кода в VS2008 и все работало, как ожидалось. Функция find возвратила итератор, указывающий на исходное значение.

Какое поведение вы видите? Возвращает ли он конец() или возвращает другое место в наборе?

+0

Это происходит, но он падает, если я пытаюсь сделать между ними ==, и я никак не могу зависеть от этого значения, потому что это всего лишь флаг отладки. В режиме выпуска они будут содержать два случайных значения. –

+0

Он возвращает правильный итератор, если он находит объект, и итератор, указывающий на 0xbaadf00d, если он не –

+0

@Kevin, если end() == 0xbaadf00d это должно быть правильное поведение. – JaredPar

0

Попробуйте компилироваться и выполняться только фрагмент кода, который вы предоставили, и я гарантирую, что вы найдете его без проблем. Проблема почти наверняка связана с ошибками выделения памяти, встречающимися в других местах вашей программы, такими как ссылки на неинициализированный указатель или указатель на объект, который был delete d.

Вы знакомы с тем, как контейнеры C++ управляют своими объектами? Они не удаляют указатели для вас. По возможности всегда безопаснее использовать контейнеры объектов, а не указатели на объекты. (Есть случаи, когда необходимы контейнеры указателей, в частности, когда вы хотите, чтобы контейнер хранил объекты разных типов из одной иерархии классов.)

5

При использовании набора stl мне нравится использовать функцию count для определения членство. Я думаю, что это облегчает чтение кода.

set<Cell*> cellSet; 

Cell* cell = new Cell();  

if (cellSet.count(cell) == 0) 
{ 
    ... 
} 
+0

Отличный подход, почему я не подумал об этом? :) –

+0

Вызов count() требует проверки каждого элемента, а find() проверяет каждый элемент только тогда, когда элемент отсутствует. Поэтому find() будет быстрее. Если читаемость является проблемой, лучше написать встроенную функцию is_member, которая принимает ассоциативный контейнер и элемент и возвращает find() == end(). –

+1

@Mark Ruzon: для std :: set, оба имеют логарифмическую сложность. Фактически, для GNU stdlibC++ реализация count в основном: {return find (x) == end()? 0: 1; } http://gcc.gnu.org/viewcvs/trunk/libstdc%2B%2B-v3/include/bits/stl_set.h?view=markup – Miles

0

Одна простая ошибка заключается в том, что вы должны испытывать не равную конце.

set<Cell*> cellSet; 
Cell* cell = new Cell(); 
if (cellSet.find(cell) != cellSet.end())  // Test NOT EQUAL to end 
{ 
    // Found item in set. 
} 

Но также следует отметить, что вы не сравниваете фактические значения ячеек, но указатель на сотовый объекты (которые могут или не могут быть то, что вы хотите). Обычно в C++ вы не склонны хранить указатели в контейнерах, так как нет никакого подразумеваемого права собственности на указатель, но иногда это нормально.

Чтобы фактически сравнить объекты, которые нужно использовать find_if() и передать предикат (функтор).

struct PointerCellTest 
{ 
    Cell& m_lhs; 
    PointerCellTest(Cell* lhs): m_lhs(lhs) {} 
    bool operator()(Cell* rhs) 
    { 
     return lhs.<PLOP> == rhs.<PLOP> 
    } 
}; 


if(find_if(cellSet.begin(),cellSet.end(),PointerCellTest(cell)) != cellSet.end()) 
{ 
    // Found item in set. 
} 
+0

В этом случае набор используется очень временно, поэтому все должно быть хорошо. Если бы это была более долгосрочная вещь, было бы установлено . Я не знал о find_if, так что спасибо! Я запомню это в следующий раз. –

Смежные вопросы