代码之家  ›  专栏  ›  技术社区  ›  Jared

删除std::set的习惯用法失败,并出现与常量相关的错误

  •  15
  • Jared  · 技术社区  · 14 年前

    编译此代码:

    void test()
    {
      std::set<int> test;
      test.insert(42);
      test.erase(std::remove(test.begin(), test.end(), 30), test.end());  // <- Line 33
    }
    

    正在编译时生成以下错误:

    $ make
    g++ -c -Wall -pedantic-errors -Wextra -Wunused -Werror a_star.cpp
    /usr/lib/gcc/i686-pc-cygwin/4.3.4/include/c++/bits/stl_algo.h: In function `_FIter std::remove(_FIter, _FIter, const _Tp&) [with _FIter = std::_Rb_tree_const_iterator<int>, _Tp = int]':
    a_star.cpp:33:   instantiated from here
    /usr/lib/gcc/i686-pc-cygwin/4.3.4/include/c++/bits/stl_algo.h:779: error: assignment of read-only location `__result.std::_Rb_tree_const_iterator<_Tp>::operator* [with _Tp = int]()'
    make: *** [a_star.o] Error 1
    
    4 回复  |  直到 14 年前
        1
  •  26
  •   Community CDub    7 年前

    std::set ,元素不可修改。所以 std::set::iterator 也不可修改。从 this 教程,第27.3.2.1节:

    在简单的关联容器中, 元素是完全不变的 嵌套类型迭代器和 因此常量迭代器是相同的。

    因此 erase-remove 习语不能照本宣科。你得写一篇文章 for std::set::erase question answer answer 具体细节,但简而言之,循环如下

    typename std::set::iterator set_iter; 
    
    for( set_iter it = s.begin(); it != s.end(); /* blank */ ) {
        if( some_condition() ) {
            s.erase( it++ );       // Note the subtlety here
        }
        else {
            ++it;
        }
    }
    
        2
  •  5
  •   AnT stands with Russia    14 年前

    Erase-remove习语不能与关联容器一起使用。关联容器不允许通过迭代器修改整个容器元素,这直接意味着变异序列操作(如 std::remove )不能应用于它们。

        3
  •  1
  •   Yakov Galka    14 年前

    您可以将代码更改为:

    test.erase(30);
    

    或者使用ArunSaha的(+1)代码来获得更复杂的标准。

        4
  •  0
  •   Benoit    14 年前

    因为集合不是纯数组,所以必须使用擦除。