1

我有这样的 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/设置/插入/

因此,作为上述代码的结果,我应该得到一个SuperSet只包含 clearIntSet的。但是“不幸的是”这段代码有效——所有IntSet的都充满了正确的值……所以我的问题是——STL集合中的insert方法在它的主体中真正做了什么?它只是复制通过引用传递给它的对象吗?传递对象或原始类型之间的这种方法的行为有什么区别?

谢谢您的回答!

4

2 回答 2

1

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

于 2012-06-07T22:46:09.207 回答
0

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

这特别适用于您传递temp的方式,superSet但在 C++11 中,您的使用变得低效。通过声明一个局部变量用作临时变量,您可以通过强制进行复制来防止使用移动语义。

SuperSet superSet;

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

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

于 2012-06-08T02:05:20.007 回答