我有以下代码:
struct Position{
int id;
Position(int _id){
id = _id;
qDebug()<<"Position"<<id;
}
~Position(){
qDebug()<<"~Position "<<id;
}
};
qDebug()<<"Init";
std::vector<Position> vec1;
vec1.emplace_back(1);
std::vector<Position> vec2;
vec2.emplace_back(2);
std::vector<Position> vec3;
vec3.emplace_back(3);
qDebug()<<"Move";
vec2 = vec1;
qDebug()<<"---------------------------------";
当我这样做时会发生什么?不应该破坏先前的对象vec2吗? 我读了这个http://www.cplusplus.com/reference/vector/vector/operator=/,但仍然没有看出旧的vec2对象应该发生什么。
输出:
Init
Position 1
Position 2
Position 3
Move
---------------------------------
~Position 3
~Position 1
~Position 1
为什么位置2根本没有被破坏?
答案 0 :(得分:4)
当您撰写vec2 = vec1
时,vec2
会复制vec1
的所有元素。如果它不复存在,怎么会这样呢?
现在,对于vec2
的元素,当他们可以复制/移动†时,不需要销毁它们。这种语言允许发生。
如果您编写自己的复制/移动赋值运算符并将调试输出放入其中,您将看到真正正在进行的操作。
†取决于C ++版本。
答案 1 :(得分:3)
分配的容器要求(C ++ 11 23.2.1)说:
a的所有现有元素都是移动分配或销毁
(实际上这只是为了赋予右值。对于左值的赋值,除了之后两个容器应该相等之外,没有任何说明。)
因此,无论原始元素是被破坏还是被元素覆盖,都取决于实现。
如果您想要销毁原始容器并无条件地将其替换为另一个容器的副本,您可以使用swap
,如下所示:
// instead of "x = y"
std::vector<Position>(y).swap(x);
这构造了一个新的向量作为y
的副本,并与x
进行交换,并且交换不会触及实际的容器元素 - 再次来自容器要求:
a.swap(b)
将在不调用单个容器元素的任何移动,复制或交换操作的情况下交换a和b的值
答案 2 :(得分:2)
为编译器生成的函数添加更多的print语句。
#include <iostream>
#include <vector>
// Don't have this on my machine so added
// to make it similar to the original
std::ostream& qDebug()
{
return std::cout;
}
struct Position{
int id;
Position(int _id){
id = _id;
qDebug()<<"Position"<<id <<"\n";
}
~Position(){
qDebug()<<"~Position "<<id <<"\n";
}
// Added this. Because if you don't define one
// the compiler will.
// Made it do the default action and print
Position(Position const& rhs)
: id(rhs.id)
{
qDebug() <<"Copy: " << id <<"\n";
}
// Added this. Because if you don't define one
// the compiler will.
// Made it do the default action and print
Position& operator=(Position const& rhs)
{
qDebug() << "Assign: Old(" << id << ") New(" << rhs.id << ")\n";
id = rhs.id;
return *this;
}
};
int main()
{
qDebug()<<"Init\n";
std::vector<Position> vec1;
vec1.emplace_back(1);
std::vector<Position> vec2;
vec2.emplace_back(2);
std::vector<Position> vec3;
vec3.emplace_back(3);
qDebug()<<"Move\n";
vec2 = vec1;
qDebug()<<"---------------------------------\n";
}
现在我们运行它:
> ./a.out
Init
Position1
Position2
Position3
Move
Assign: Old(2) New(1)
---------------------------------
~Position 3
~Position 1
~Position 1
所以我们可以看到Position(2)被一个赋值放置,该赋值将(1)放入值中。最重要的是要注意构造函数和析构函数的匹配。
答案 3 :(得分:0)
您的班级职位没有明确定义的复制赋值运算符。当这句话
vec2 = vec1;
执行复制赋值运算符,用于调用两个向量共有的元素。因此vec2 [0]代替vec1 [0](即vec1 [0]被分配给vec2 [0])。这意味着旧元素vec2 [0]的id等于1.没有任何内容被删除。
当析构函数被调用时,vec2 [0]的id等于1且vec1 [0]的id等于1,因为该元素已分配给vec2 [0]。输出显示了这一点。