std :: vector = std :: vector时发生了什么?

时间:2013-12-09 19:56:34

标签: c++ vector

我有以下代码:

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根本没有被破坏?

4 个答案:

答案 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]。输出显示了这一点。