【问题标题】:Modifying elements in std::set修改 std::set 中的元素
【发布时间】:2015-07-01 06:17:29
【问题描述】:

我有以下代码-:

int main()
{
    set<string> s;
    s.insert( "asas" );
    s.insert( "abab" );

    for ( auto item : s )
    {
        cout << item << "\n";
        reverse( item.begin(), item.end() );
    }

    cout << "\n";

    for ( auto item : s )
    {
        cout << item << "\n";
    }
}

输出-:

abab
asas

abab
asas

reverse() 函数根本没有修改集合的元素。
我怀疑集合中的元素根本无法修改。但是,如果是这种情况,为什么编译器本身不首先给出错误?

我在 Windows 7 上使用带有 -std=c++14 标志的 TDM-GCC 4.9.2。

【问题讨论】:

  • 您正在对项目的副本进行操作,set 中的原件没有更改。使用迭代器直接操作它们。
  • 集合中的项目按特定顺序排序。这就是为什么无论集合有多大,插入和移除总是相对较快的原因。您可以指定所需的顺序,但不能更改它。如果项目的顺序对您很重要,请使用顺序容器,例如向量。

标签: c++ gcc stl std stdset


【解决方案1】:

std::set 的元素是const。如果你想改变元素,你需要进行插入和删除以使容器处于你想要的状态。

在您的代码示例中:

for (auto item : s)

被翻译成类似的东西:

for (auto iter = s.begin(); iter != s.end(); ++iter)
{
    auto item = *iter; // Copy!
    // loop body
}

循环归纳变量itemset 中元素的副本,而不是对set 中实际元素的引用。因此,set 不会更改。要更改集合,您需要调用set 的成员函数,例如inserterase

在这里将item 更改为&amp;item 无济于事;如果你这样做,你会得到一个编译时错误,因为集合的元素是 const,所以你不能对它们应用reverse

【讨论】:

    【解决方案2】:

    这个基于范围的循环会复制集合中的每个元素:

    for ( auto item : s )
    

    这就是为什么您可以在循环中修改item 而不会触发编译器错误。

    如果您想修改容器的元素,您需要一个参考。使用它确实会导致编译器错误,因为无法修改集合的元素:

    for ( auto& item : s )
    {
      // s is a set. You cannot modify item
    

    【讨论】:

      【解决方案3】:

      std::set 中的对象是 const,因为它们被用作键。所以你不能像这样修改集合中的对象。

      【讨论】:

        猜你喜欢
        • 2017-09-06
        • 2010-10-28
        • 2018-01-11
        • 2020-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多