Как иметь набор структур в С++
У меня есть структура, которая имеет уникальный ключ. Я хочу вставить экземпляры этих структур в набор. Я знаю, что для этого < оператор должен быть перегружен, чтобы набор мог провести сравнение, чтобы выполнить вставку.
Не работает следующее:
#include <iostream>
#include <set>
using namespace std;
struct foo
{
int key;
};
bool operator<(const foo& lhs, const foo& rhs)
{
return lhs.key < rhs.key;
}
set<foo> bar;
int main()
{
foo *test = new foo;
test->key = 0;
bar.insert(test);
}
Ответы
Ответ 1
Это может помочь:
struct foo
{
int key;
};
inline bool operator<(const foo& lhs, const foo& rhs)
{
return lhs.key < rhs.key;
}
Если вы используете пространства имен, хорошей практикой является объявление функции operator<()
в том же пространстве имен.
Для полноты после вашего редактирования и, как указывали другие, вы пытаетесь добавить foo*
, где ожидается foo
.
Если вы действительно хотите иметь дело с указателями, вы можете обернуть foo*
в класс интеллектуального указателя (auto_ptr
, shared_ptr
,...).
Но обратите внимание, что в обоих случаях вы теряете преимущество перегруженного operator<
, который работает на foo
, а не на foo*
.
Ответ 2
struct Blah
{
int x;
};
bool operator<(const Blah &a, const Blah &b)
{
return a.x < b.x;
}
...
std::set<Blah> my_set;
Однако мне не нравится перегрузка operator<
, если она не делает интуитивного смысла (действительно ли имеет смысл сказать, что один Blah
меньше "другого Blah
?). Если это не так, я обычно предоставляю функцию пользовательского сравнения:
bool compareBlahs(const Blah &a, const Blah &b)
{
return a.x < b.x;
}
...
std::set<Blah,compareBlahs> my_set;
Ответ 3
Вы можете перегрузить operator <
внутри класса, а также,
struct foo
{
int key;
bool operator < (const foo &other) const { return key < other.key; }
};
В вашем вопросе, если вы хотите использовать set<foo> bar;
как объявление, тогда вы должны вставить значение как,
bar.insert(*test);
Но это не будет хорошей идеей, поскольку вы делаете избыточную копию.
Ответ 4
см. ereOn ответ, это правильно.
Реальная проблема в вашем коде:
foo *test = new foo;
test->key = 0;
bar.insert(test);
Вы вставляете указатель в набор, а не в структуру. Измените insert
на:
bar.insert( *test );
// ^
EDIT: но тогда вам нужно delete foo
, так как оно будет скопировано в set
. Или просто создать его в стеке (с помощью set
с указателями это не очень хорошая идея, потому что расположение будет "странным" - set
будет сортироваться в соответствии с адресами указателей)
Ответ 5
Лучше всего сделать foo конструктор:
struct foo
{
foo(int k) : key(k) { }
int key;
};
Затем добавить, а не...
foo *test = new foo;
test->key = 0;
bar.insert(test); // BROKEN - need to dereference ala *test
// WARNING: need to delete foo sometime...
... вы можете просто использовать:
bar.insert(foo(0));
Ответ 6
Проблема не в вашем наборе; это в вашем объекте test
. Вы используете Java-стиль там. В С++ мы просто пишем:
set<foo> bar;
int main()
{
foo test; // Local variable, goes out of scope at }
test.key = 0;
bar.insert(test); // Insert _a copy of test_ in bar.
}
Ответ 7
В С++ 11 мы можем использовать лямбда-выражения, я использовал этот способ, который похож на то, что было дано @Oliver.
#include <set>
#include <iostream>
#include <algorithm>
struct Blah
{
int x;
};
int main(){
auto cmp_blah = [](Blah lhs, Blah rhs) { return lhs.x < rhs.x;};
std::set<Blah, decltype(cmp_blah)> my_set(cmp_blah);
Blah b1 = {2};
Blah b2 = {2};
Blah b3 = {3};
my_set.insert(b1);
my_set.insert(b2);
my_set.insert(b3);
for(auto const& bi : my_set){
std::cout<< bi.x << std::endl;
}
}
демонстрация