Вызов деструктора в конструкторе класса с вектором - PullRequest
0 голосов
/ 26 января 2020

У меня есть следующий класс, который просто оборачивает массив и добавляет с конструктором некоторые элементы к нему:

class myArray {
public:
    myArray();
    myArray(int a, int b);
    myArray(int a, int b, int c);
    myArray(myArray&& emplace);

    ~myArray();

    int& operator [](int id);

private:
    int *data;
};

myArray::myArray() {
    data = new int[1];
    data[0] = 0;
}

myArray::myArray(int a, int b) {
    data = new int[3];
    data[0] = 0;
    data[1] = a;
    data[2] = b;
}

myArray::myArray(int a, int b, int c) {
    data = new int[4];
    data[0] = 0;
    data[1] = a;
    data[2] = b;
    data[3] = c;
}

myArray::~myArray() {
    std::cout << "Destructor"<<std::endl;
    delete[] data;
}

int& myArray::operator [](int id) {
    return data[id];
}

myArray::myArray(myArray&& emplace) : data(std::move(emplace.data)) {}

Кроме того, у меня есть второй класс, который содержит вектор элементов первого класса (myArray).

class Queue {
public:
    Queue();

private:
    std::vector<myArray> _queue;
};

Queue::Queue {
    _queue.reserve(1000);
    for(int a = 0; a < 10; a++)
        for(int b = 0; b < 10; b++)
            for(int c = 0; c < 10; c++)
                        _queue.emplace_back(a,b,c);
}

Мой вопрос здесь такой: почему деструктор вызывается для элементов myArray в конце конструктора Queue? Объект Queue все еще жив в моей основной программе, но деструктор myArray освобождает выделенную память, и в результате я получаю ошибку сегментации.

Есть ли способ избежать вызова деструктора или, скорее, вызывать его до тех пор, пока в конце времени жизни объектов Queue?

1 Ответ

3 голосов
/ 26 января 2020

Ваш конструктор перемещения не устанавливает data в null для перемещенного объекта, поэтому при удалении перемещенного объекта он попытается освободить данные.

Если у вас есть c ++ 14, вы можете используйте std::exchange для реализации этого:

myArray::myArray(myArray&& emplace)
 : data{std::exchange(emplace.data, nullptr)})
{}

В противном случае вам нужно сделать:

myArray::myArray(myArray&& emplace)
 : data{emplace.data)
{
  emplace.data = nullptr;
}

Конструктор перемещения будет вызываться std::vector, так как он перераспределяется для увеличения его емкости, когда Вы звоните emplace_back. Выполняется что-то вроде следующих шагов:

  1. Выделение новой памяти для хранения элементов
  2. Перемещение конструкции с использованием размещения новых элементов в новой памяти из элементов в предыдущей памяти
  3. Уничтожить элементы в предыдущей памяти
  4. Отменить выделение предыдущей памяти
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...