簡體   English   中英

為什么 std::set 似乎強制使用 const_iterator?

[英]Why does std::set seem to force the use of a const_iterator?

考慮下面的簡單程序,它嘗試使用對集合中元素的非常量引用來遍歷集合的值:

#include <set>
#include <iostream>

class Int
{
public:
   Int(int value) : value_(value) {}
   int value() const { return value_; }
   bool operator<(const Int& other) const { return value_ < other.value(); }
private:
   int value_;
};

int
main(int argc, char** argv) {
   std::set<Int> ints;
   ints.insert(10);
   for (Int& i : ints) {
      std::cout << i.value() << std::endl;
   }
   return 0;
}

編譯時,我從 gcc 收到錯誤:

test.c: In function ‘int main(int, char**)’:
test.c:18:18: error: invalid initialization of reference of type ‘Int&’ from expression of type ‘const Int’  
for (Int& i : ints) {  
              ^  

是的,我知道我實際上並沒有嘗試修改 for 循環中的元素。 但關鍵是我應該能夠獲得在循環內使用的非 const 引用,因為集合本身不是 const 限定的。 如果我創建一個 setter function 並在循環中使用它,我會得到同樣的錯誤。

集合就像沒有值的地圖,只有鍵。 由於這些鍵用於加速集合操作的樹,因此它們無法更改。 因此,所有元素必須是const,以防止底層樹的約束被破壞。

std::set使用包含的值來形成快速數據結構(通常是紅黑樹)。 更改值意味着需要更改整個結構。 因此,強制conststd::set阻止您將其推入不可用狀態。

cpp參考

在集合中,元素的值也標識它(值本身是類型T的鍵),並且每個值必須是唯一的。 集合中元素的值不能在容器中修改一次(元素總是const ),但可以在容器中插入或刪除它們。

行為是設計的。

給你一個非const迭代器可以激發你改變集合中的元素; 隨后的迭代行為將是未定義的。

請注意,C ++標准說set<T>::iteratorconst所以老式的前C ++ 11方法仍然不起作用。

添加內特的答案

集合就像 map,沒有值,只有鍵。 由於這些鍵用於加速集合操作的樹,因此它們不能更改。 因此,所有元素都必須是const以防止底層樹的約束被破壞。

對於 C++17 有新的extract成員 function,因此const_cast的替代方案可能是:

#include <iostream>
#include <string_view>
#include <set>

struct S
{
  int used_for_sorting;
  bool not_used_for_sorting;

  bool operator<(const S &rhs) const
  { return used_for_sorting < rhs.used_for_sorting; }
};

void print(std::string_view comment, const std::set<S> &data)
{
  std::cout << comment;
  for (auto datum : data)
    std::cout << " {" << datum.used_for_sorting
              << ',' << datum.not_used_for_sorting
              << '}';

  std::cout << '\n';
}

int main()
{
  std::set<S> cont = {{1, false}, {2, true}, {3, false}};

  print("Start:", cont);

  // Extract node handle and change key
  auto nh = cont.extract({1, false});
  nh.value().not_used_for_sorting = true;

  print("After extract and before insert:", cont);

  // Insert node handle back
  cont.insert(std::move(nh));

  print("End:", cont);
}

可能用作熱修復。 一般來說,很難看出比std::map有任何優勢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM