STL 集合的插入方法是否复制传递对象的值?

Does insert method of STL's set copy the value of passed objects?

本文关键字:对象 是否 集合 插入 方法 STL 复制      更新时间:2023-10-16

我有这么C++的代码(请不要问为什么它看起来这么丑;) - 你必须相信,由于代码的进一步部分,它确实有意义):

IntSet temp;
SuperSet superSet;
for (uint i = 0; i < noItems; i++) {
        temp.insert(i);
        superSet.insert(temp);
        temp.clear();
}

它用于准备noItems个整数集合(IntSet,每个集合包含一个整数值)并将其插入到另一个集合(SuperSet)。这两个集合的定义如下:

typedef unsigned int DataType;
typedef std::set<DataType> IntSet;
typedef std::set<IntSet> SuperSet;

对我来说,这段代码不应该按预期工作,因为就在插入tempsuperSet之后,我正在清除temp,我发现insert正在获得一个引用作为其参数:pair<iterator,bool> insert ( const value_type& x ); (http://www.cplusplus.com/reference/stl/set/insert/)

因此,作为上面介绍的代码的结果,我应该得到一个仅包含清除IntSetSuperSet。但是"不幸的是"这段代码有效 - 所有IntSet都填充了正确的值......所以我的问题是 - STL 集合中的插入方法在其主体中真正做什么?它是否只是复制通过引用传递给它的对象?传递对象类型或基元类型之间的此方法行为有何区别?

感谢您的回答!

insert()采用引用参数以避免在传递参数时复制。 但它会在将项目存储在集合中时创建副本。 这就是为什么clear()在这种情况下可以工作的原因。 此外,在这两种情况下都是如此,因此即使您"重用"temp,也会有单独的副本superSet

您的 SuperSet 声明按值存储IntSet,因此插入新元素的唯一方法是制作副本。由于对原始IntSet进行了更改,因此不会反映在副本中。

这特别适用于您将temp传递给superSet的方式,但在 C++11 中,您的使用效率变得低下。通过声明要用作临时的局部变量,可以通过强制创建副本来防止使用 move 语义。

SuperSet superSet;
for (DataType i = 0; i < noItems; i++)
{
    superSet.insert(IntSet(&i, &i + 1));
}

打折优化 编译器将创建一个临时IntSet并使用单个元素对其进行初始化。因为编译器知道这是一个临时的,所以它可以使用移动构造函数插入值。这将对传递的IntSet执行浅拷贝,并将其值重置为默认状态(即指向 nullptr 的指针),从而导致移动