std::vector с элементами, размещенными в куче - мне нужно правило 5?

Если у меня есть класс с такими членами:

class MyClass {
public:
    void set_my_vector() {
        for (int ind = 0; ind < 3; ++ind) {
            my_vector.push_back(new MyStruct(i, i*2));
        }
    }
private:
    struct MyStruct {
        int num_a;
        int num_b;
        MyStruct(int i, int j) : num_a(i), num_b(j) {}
    };
    std::vector<MyStruct*> my_vector;
};

Нужно ли мне писать функции по правилу пяти, или std:: vector позаботится о глубоком копировании и удалении элементов, размещенных в куче?

РЕДАКТИРОВАТЬ: В следующем коде используется конструктор копирования по умолчанию, поэтому я предполагаю, что после того, как я скопирую объект my_class1 в объект my_class2, элементы my_class1.my_vector и my_class2.my_vector будут одинаковыми, потому что были скопированы указатели MyStruct, но не сами данные. Однако выходные данные показывают, что они не совпадают. Вы можете запустить код здесь: https://onlinegdb.com/S1pK9YE4v

#include <iostream>
#include <vector>

class MyClass {
public:    
    void fill_my_vector(int i, int j) {
        my_vector.clear();
        for (int ind = 0; ind < 3; ++ind) {
            my_vector.push_back(new MyStruct(i, j));
        }
    }

    void print () {
        for (int ind = 0; ind < 3; ++ind) {
            std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
        }
        std::cout << std::endl;
    }
private:
    struct MyStruct {
        MyStruct (int i, int j) :
        int1(i), int2(j)
        {}
    
        int int1;
        int int2;
    };

    std::vector<MyStruct*> my_vector;
};

int main()
{
    MyClass my_class1;
    my_class1.fill_my_vector(42, 43);

    std::cout << "my_class1: " << std::endl;
    my_class1.print();

    MyClass my_class2 = my_class1;
    my_class2.fill_my_vector(12, 13);

    std::cout << "my_class2: " << std::endl;
    my_class2.print();

    std::cout << "my_class1: " << std::endl;
    my_class1.print();

}

EDIT2: я знаю об умных указателях. Меня особенно интересует, что произойдет, если я буду использовать необработанные указатели.

2 ответа

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

Кроме того, рассмотрите возможность изменения объявления вектора с

std::vector<MyStruct*> my_vector;

к

std::vector<std::unique_ptr<MyStruct>> my_vector;

так что он действительно правильно владеет объектами, выделенными кучей. Это изменение поможет вам не писать деструктор.

Нет std::vectorне заботится о глубоком копировании ваших объектов, хранящихся по указателю. У вас есть несколько возможностей решить эту проблему:

  • хранить MyStruct по стоимости.
  • хранить std::unique_ptr<MyStruct>.
  • хранить std::shared_ptr<MyStruct>.

Обратите внимание, потому что MyStruct содержит только поля примитивных типов, ни конструктор копирования, ни оператор присваивания, ни деструктор не нужны, иначе вам придется их реализовать, реализация по умолчанию, которую компилятор сгенерирует автоматически, будет достаточно хорошей.

Другие вопросы по тегам