std :: vector не вызывает деструктор при переназначении - PullRequest
0 голосов
/ 15 мая 2018

Я пытаюсь использовать std::vector для хранения некоторых S экземпляров.Однако, когда я переназначаю элемент вектора, деструктор не вызывается для предыдущего арендатора:

Код

#include <iostream>
#include <vector>

struct S {
    int index_;
    S(int index) : index_(index) {
        std::cout << "Calling S " << index_ << " constructor\n";
    }
    S(const S& other) : index_(other.index_) {
        std::cout << "Calling S " << index_ << " copy constructor\n";
    }
    ~S() {
        std::cout << "Calling S " << index_ << " destructor\n";
    }
};


int main()
{
    std::vector<S> v;
    v.reserve(10); // Let's not worry about copy constructors
    std::cout << "# Created vector\n";
    v.emplace_back(0);
    v.emplace_back(1);
    v.emplace_back(2);
    std::cout << "# Replacing\n";
    v[1] = S(3); // This doesn't destruct S(1) that was here

    // I can manually call the destructor before I reassign but is that
    // something I should do()?
    // v[1].~S();

    std::cout << "# End scope\n";
}

Вывод

# Created vector
Calling S 0 constructor
Calling S 1 constructor
Calling S 2 constructor
# Replacing
Calling S 3 constructor
Calling S 3 destructor
# End scope
Calling S 2 destructor
Calling S 3 destructor
Calling S 0 destructor

Вопрос

Похоже, что S(1) в позиции 1 никогда не разрушается.Как я отмечал в коде, я могу вручную вызвать деструктор, прежде чем переназначить его, но я не уверен, что это хорошая идея.Это так, и если нет, что вы предлагаете?Кроме того, есть ли

Соединения с тем, что я действительно хочу

В реальном коде я играю с бинарными деревьями, и я подумал, что было бы интересно сделать узлы членами вектора.и указывать друг на друга с помощью индексов в векторе (получая от меня непрерывные преимущества кэша памяти, 32-битные индексы вместо 64-битных указателей и что-то другое, с чем можно поиграть).Но в конце концов мне нужно выполнить некоторые операции с деревом, что означает перемещение / удаление элементов, поэтому я хочу, чтобы деструктор вызывался для удаления элемента (и я буду использовать std::set или что-то еще, чтобы отслеживать дыры ввектор).

1 Ответ

0 голосов
/ 15 мая 2018

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

struct S {
    int index_;
    S(int index) : index_(index) {
        std::cout << "Calling S " << index_ << " constructor\n";
    }
    S(const S& other) : index_(other.index_) {
        std::cout << "Calling S " << index_ << " copy constructor\n";
    }

    // added
    S& operator=(const S& other) {
        if (this == &other) { return *this; }
        std::cout << "Calling S " << index_ << " copy assignment\n";
        index_ = other.index_;
        return *this;
    }

    ~S() {
        std::cout << "Calling S " << index_ << " destructor\n";
    }
};

Назначение не уничтожает существующий объект, оно назначает ему. Вы можете воспроизвести это в более простом случае

int main() {
    S s1(1);
    s1 = S(2); // assignment, not destruction/construction. same idea
}

Если вашему объекту принадлежит какой-то ресурс, вы обнаружите, что оператор присваивания делает схожие действия как с деструктором, так и с конструктором копирования. Вы можете прочитать о правиле 3 здесь , которое расширяется до правила 5 с добавлением операций перемещения.

...