set中如何存儲自定義對象?

  • 2020 年 3 月 11 日
  • 筆記

如何在set中存儲自定義對象?

set是什麼

假設你已經在C++中使用過set,那麼你應該知道,set中存儲的元素是去重的。比如:

//來源:公眾號:編程珠璣  //作者守望先生  #include <iostream>  #include <set>  using namespace std;  int main()  {      set<int> a;      a.insert(123);      a.insert(111);      a.insert(111);      a.insert(2);      //遍歷set      for(auto &it:a)      {          cout<<it<<endl;      }      return 0;  }  

輸出結果:

2  111  123  

雖然插入了兩次111,但是最終只會存儲一個,也就是最後set中只有三個元素。

如何在set中存儲自定義對象

有時候,我們可能想通過set做一下去重的事情,對於基本數據類型,set都能很好地處理。我們看看對於自定義的對象,它的結果如何呢?

//來源:公眾號【編程珠璣】  //作者:守望先生  #include <iostream>  #include <set>  using namespace std;  class MyObject  {      //方便起見,暫時設置為public      public:          int id;          string data;      public:          MyObject(int i,string d):id(i),data(d){}  };  int main()  {        set<MyObject> a;      a.insert(MyObject(123,"123"));      a.insert(MyObject(111,"111"));      a.insert(MyObject(111,"111"));      a.insert(MyObject(2,"2"));      for(auto &it:a)      {          cout<<it.id<<endl;      }      return 0;  }  

很不幸,還沒來得及運行,先報錯了。

error: no match for 『operator<』 (operand types are 『const MyObject』 and 『const MyObject』)  

從報錯資訊我們可以推斷出,它是需要調用『operator<』,也就是說,我們需要重載操作符<,讓它可以用來判斷元素是否重複。那麼重載它有什麼原則呢? 關於操作符的重載,可以參考《什麼是運算符的重載?》。

重載原則

注意,這裡是僅僅介紹去重時的原則,這裡暫時未涉及排序。準則細看有很多,這裡總結起來就是: 兩個元素如果沒有任何一個小於另外一個,則他們視為重複。 假設比較函數是f(x,y),那麼當f(x,y)和f(y,x)都返回false的時候,認為他們是重複的。

調用原則

其實,set容器在判定已有元素a和新插入元素b是否相等時,是這麼做的:

  • 將x作為左操作數,y作為右操作數,調用比較函數,並返回比較值
  • 將x作為左操作數,y作為右操作數,再調用一次比較函數,並返回比較值。 如果他們兩個都返回false,則認為重複,重複的元素不會被插入到容器中。

當然需要注意的是,如果x<y為true,那麼x>y應為false,所以這裡應該避免兩個都返回true,否則將會出現未知行為。

參考實現

對於我們前面的例子來說,假設id重複,則認為對象是相同的,那麼重載的<參考實現如下:

  bool operator<(const MyObject &a) const      {          if(this->id == a.id)          {              return false;          }          else          {              return this->id > a.id;          }      }  

添加之後,重新運行,就符合預期,可以對自定義對象去重啦!

總結

對於自定義對象存儲在set中,如果我們希望它按照我們指定的規則去重,就可能需要重載operator<了,那麼是不是只有這一種方法呢?