std::transform 需要特别注意集合

Und*_*ior 3 c++ stl stl-algorithm

我不明白为什么这段代码会编译:

#include <set>
#include <list>
#include <algorithm>

int modify(int i)
{
 return 2*i;
}

int main (int args, char** argv)
{
  std::set<int> a;
  a.insert(1);
  a.insert(2);
  a.insert(3);

  std::list<int> b;  // change to set here

  std::transform(a.begin(), a.end(), b.begin(), modify);   // line 19
}
Run Code Online (Sandbox Code Playgroud)

同时,如果我只是将 b 的类型从 更改为std::list<int>std::set<int>它会在编译时(第 19 行)失败并显示错误:read-only variable is not assignmentable。要将 b 用作集合,我需要将变换线更改为

std::transform(a.begin(), a.end(), std::inserter(b, b.begin()), modify);
Run Code Online (Sandbox Code Playgroud)

这是为什么?我以某种方式猜测原因与 set 是一个关联容器而 list 是一个序列容器这一事实有关,但我在这里可能完全偏离了重点。

编辑

我忘了提及:我使用默认标准 (c++98) 在 gcc 3.4.2 和 llvm 3.3 上尝试过这个。我使用 c++03 在 llvm 3.3 上再次尝试,我得到了相同的行为。

Ste*_*sop 5

在您的代码中,没有std::insertertransform分配给*b.begin(). 在这种情况下,set这是对元素的 const 引用(C++11 起)。因此,编译时错误。

在这种情况下,list它仍然分配给*b.begin(),它编译但具有未定义的行为,因为列表的大小为 0。因此b.begin()可能不会取消引用。

您是正确的,这与set作为关联容器而是list序列的事实有关。关联容器不允许您修改用作键的元素部分。在该set部分元素的情况下,因为map您可以修改值但不能修改键。

重点std::inserter是安排它而不是通过迭代器分配,它调用insert.