我有这样的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;
对我来说,此代码不应按预期工作,因为在将temp
插入superSet
之后我正在清除temp
,我发现insert
获取参考作为其参数:pair<iterator,bool> insert ( const value_type& x );
(http://www.cplusplus.com/reference/stl/set/insert/)
因此,作为上述代码的结果,我应该得到仅包含已清除SuperSet
的{{1}}。但“不幸的是”这段代码有效 - 所有IntSet
都填充了正确的值......所以我的问题是 - 来自STL集合的插入方法在其体内是做什么的?它是否只是复制通过引用传递给它的对象?这个方法在传递对象或基元类型之间的行为有什么不同?
感谢您的回答!
答案 0 :(得分:1)
insert()
接受引用参数以在传递参数时避免复制。但是在将项目存储在集合中时会创建副本。这就是clear()
在这种情况下可以工作的原因。此外,在这两种情况下都是如此,因此即使您“重复使用”temp
,superSet
答案 1 :(得分:0)
您按{值{1}}存储SuperSet
的声明,因此插入新元素的唯一方法是制作副本。由于副本已对原始IntSet
进行更改,因此不会反映在副本中。
这特别适用于您将IntSet
传递给temp
的方式,但在C ++ 11中,您的使用效率低下。通过声明一个局部变量用作临时变量,可以通过强制复制来阻止使用移动语义。
superSet
折扣优化编译器将创建一个临时SuperSet superSet;
for (DataType i = 0; i < noItems; i++)
{
superSet.insert(IntSet(&i, &i + 1));
}
并使用单个元素对其进行初始化。因为编译器知道这是临时的,所以它可以使用移动构造函数插入值。这将执行IntSet
传递的浅表副本,并将其值重置为默认状态(即指向nullptr的指针),从而导致移动。