2013-12-09 6 views
0

У меня есть следующий код:Что произошло, когда std :: vector = std :: 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=/, но все еще не undestand, что должно произойти со старым объектом vec2.

Выход:

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

Почему позиция 2 не разрушается вообще?

+0

Добавить операторы печати в конструкторе копирования. 'Position (Position const & rhs): id (rhs.id) {std :: cout <<" Copy Construct "<< id <<" \ n ";}' и присвоение 'Position & operator = (Position const & rhs) { std :: cout << "Assign." << id << "заменено на" << rhs.id << "\ n"; id = rhs.id; return * this;} 'и повторить попытку. –

ответ

4

Когда вы пишете vec2 = vec1, vec2 берет на себя копии всех элементов vec1. Как это могло произойти, если бы оно прекратилось?

Теперь, как для vec2 «s элементов, они не должны быть уничтожены, когда они могут быть скопированы/перемещены & кинжалом; вместо. Язык позволяет либо произойти.

Если вы пишете свои собственные операторы присваивания копий/перемещений и помещаете в них вывод отладки, вы увидите, что происходит действительно.

& dagger; В зависимости от версии на C++.

+0

Другими словами - это нормально, я не получаю утечки? – tower120

+0

@ tower120: Нет, утечки нет. Как я и предложил, попробуйте сами! –

+0

Добавление Move изменяет поведение. В настоящее время позиция не имеет операций перемещения. Поскольку компилятор не генерирует один, если деструктор определен пользователем. –

3

Требования контейнеров (11 23.2.1 C++) для присвоения сказать:

Все существующие элементы являются либо переместить назначенные или уничтожены

(На самом деле это только для присвоения значения r. Для присвоения lvalue нет никакой спецификации, кроме того, что два контейнера должны быть равны после этого.)

Таким образом, это зависит от того, будут ли оригинальные элементы ts уничтожаются или перезаписываются по стилю.

Если вы хотите, чтобы уничтожить оригинальный контейнер и заменить его копией другого контейнера, безусловно, вы можете использовать swap так:

// instead of "x = y" 

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

Это создает новый вектор в качестве копии y и свопы, что с x и свопингом не касаются фактических элементов контейнера - снова от требований контейнера:

a.swap(b) променяет значение а и Ь, не прибегая к какому-либо перемещать, копировать или операции подкачки на отдельных элементах контейнера

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]. Результат показывает это.

2

Добавление дополнительных операторов печати для сгенерированных функций компилятора.

#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 

Таким образом, мы можем видеть, что позиция (2) получил перезаписаны присвоения, помещенного (1) в стоимость. Самое главное отметить, что число конструкторов и деструкторов соответствует.

+0

Зачем компилятору нужен оператор = двигаться? Почему вместо этого он не использует конструктор перемещения? – tower120

+0

@ tower120: потому что, когда вы определяете деструктор, компилятор не будет генерировать конструктор перемещения автоматически. Это предотвратит компилятор для генерации при перемещении по векторам. Если вы определяете конструктор Move, тогда у компилятора есть возможность использовать перемещение по вектору. Обратите внимание, что этот пример немного надуман, поскольку деструктор просто печатает информацию (так что у этого класса в действительности будет конструктор перемещения). –

+0

Но обратите внимание: в этом случае вы не можете использовать move. Это связано с тем, что старый вектор все еще вокруг и полезен.Перемещение содержимого из одного массива в другой привело бы к тому, что массив rhs был бы в неопределенном состоянии (или элементы находятся в неопределенном состоянии). –

Смежные вопросы