tower120
tower120

Reputation: 5255

What happened when do std::vector = std::vector?

I have the following code:

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()<<"---------------------------------";

What happens when I do = ? Shouldn't previous object vec2 be destructed? I read this http://www.cplusplus.com/reference/vector/vector/operator=/, but still not undestand what should happend with old vec2 object.

Output:

Init
Position 1
Position 2
Position 3
Move
---------------------------------
~Position  3
~Position  1
~Position  1

Why Position 2 not destructed at all?

Upvotes: 0

Views: 302

Answers (4)

Kerrek SB
Kerrek SB

Reputation: 476950

The container requirements (C++11 23.2.1) for assignment say:

All existing elements of a are either move assigned to or destroyed

(Actually that is only for assignment of an rvalue. For assignment of an lvalue, there's no specification at all other than that the two containers shall be equal afterwards.)

So it's up to the implementation whether the original elements are destroyed, or overwritten element-wise.

If you want to destroy the original container and replace it with a copy of another container unconditionally, you can use swap like so:

// instead of "x = y"

std::vector<Position>(y).swap(x);

This constructs a new vector as a copy of y and swaps that with x, and swapping doesn't touch the actual container elements - again from the container requirements:

a.swap(b) shall exchange the values of a and b without invoking any move, copy, or swap operations on the individual container elements

Upvotes: 3

Loki Astari
Loki Astari

Reputation: 264351

Adding more print statements for compiler generated functions.

#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";
}

Now we run it:

> ./a.out
Init
Position1
Position2
Position3
Move
Assign: Old(2)  New(1)
---------------------------------
~Position 3
~Position 1
~Position 1

So we can see that Position(2) got overwritten by an assignment that placed (1) into the value. The most important thing to note is that the number of constructors and destructors match.

Upvotes: 2

Vlad from Moscow
Vlad from Moscow

Reputation: 310930

Your class position has no explicitly defined copy-assignment operator. When this statement

vec2 = vec1;

is executed the copy assignment operator for elements the number of which is common for the both vectors is called. So vec2[0] is substituted for vec1[0] (that is vec1[0] is assigned to vec2[0]). It means that old element vec2[0] gets id equal to 1. Nothing is deleted.

When destructors are called vec2[0] has id equal to 1 and vec1[0] has id equal to 1 because this element was assigned to vec2[0]. The output shows this.

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385108

When you write vec2 = vec1, vec2 takes on copies of all the elements of vec1. How could it do that if it ceased to exist?

Now, as for vec2's elements, they don't need to be destroyed when they can be copied/moved over instead. The language allows either to happen.

If you write your own copy/move assignment operators and put debug output in those, you'll see what's really going on.

Depending on C++ version.

Upvotes: 4

Related Questions