2

У меня есть метод класса, который работает с копией объекта (* это, если быть точным). Утечки происходят в перегруженном операторе присваивания - это то, о чем говорит Visual Leak Detector. То, что я делаю, работает с копией, и если работа выполнена удовлетворительно, я копирую этот вновь созданный объект обратно. Я также реализовал собственный деструктор, конструктор копирования и оператор присваивания, потому что проблема возникает с динамически распределенной памятью, очевидно. Мой опыт работы с C++ довольно ограничен, поэтому в коде могут быть какие-то злые вещи.C++ - перегруженные операторы памяти оперативной памяти

При необходимости я предоставит дополнительную информацию.

Проблематичный метод:

bool Grid::SurroundShipSquares(int top, int bottom, int left, int right) 
{ 
    // copying itself 
    Grid gridCopy(*this); 
    Square** squaresCopy = gridCopy.GetSquares(); 
    for (int i = top; i <= bottom; ++i) 
    { 
     for (int j = left; j <= right; ++j) 
     { 
      if (squaresCopy[i][j].GetState() != SquareState::Vacant) 
       return false; 
      (squaresCopy[i][j]).SetState(SquareState::Unoccupiable); 
     } 
    } 
    // the problem occurs here 
    *this = gridCopy; 
    return true; 
} 

Копировать конструктор:

Grid::Grid(const Grid& source) 
{ 
    _position = source._position; 
    _size = source._size; 
    int dimensions = static_cast<int>(_size); 
    _squares = new Square*[dimensions]; 
    for (int i = 0; i < dimensions; ++i) 
    { 
     _squares[i] = new Square[dimensions]; 
     for (int j = 0; j < dimensions; ++j) 
     { 
      _squares[i][j] = source._squares[i][j]; 
     } 
    } 
} 

Назначение Оператор:

Grid& Grid::operator=(const Grid& source) 
{ 
    if (this == &source) 
     return *this; 
    _position = source._position; 
    _size = source._size; 
    int dimensions = static_cast<int>(_size); 
    _squares = new Square*[dimensions]; 
    for (int i = 0; i < dimensions; ++i) 
    { 
     _squares[i] = new Square[dimensions]; 
     for (int j = 0; j < dimensions; ++j) 
     { 
      _squares[i][j] = source._squares[i][j]; 
     } 
    } 
    return *this; 
} 

деструктор:

Grid::~Grid() 
{ 
    int dimensions = static_cast<int>(_size); 
    for (int i = 0; i < dimensions; ++i) 
    { 
     delete[] _squares[i]; 
    } 
    delete[] _squares; 
} 
+5

Сохраните все проблемы и используйте вместо этого [copy-and-swap idiom] (http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom). –

+1

Не делайте этого. – Puppy

+0

К сожалению, этот вопрос стал еще одной демонстрацией того, почему мое участие в этой части сети SE в последнее время выпало. –

ответ

5

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

Использование std::vector. Этот класс автоматически будет управлять всей памятью для вас, освобождая вас от необходимости делать это самостоятельно. Это значительно упростит ваш код, а также сделает его правильным.

Кроме того, проверка самонаведения является древним анти-шаблоном. Не включайте проверку для самостоятельного назначения. Если ваш оператор присваивания (в большинстве случаев вам не нужно писать самостоятельно с помощью управления памятью std::vector), он не может обрабатывать самоназначение без специального случая, он не работает.

+0

Могу ли я использовать valarray для хранения 2D-матриц? Я спрашиваю, потому что это будет положительно оставаться с фиксированными измерениями. Например, например: std :: valarray ()> _squares. – Venom

+0

Вы могли бы сделать, но вместо этого рассмотрите boost :: multi_array. Ваш существующий код в любом случае эквивалентен вектору векторов. std :: valarray - это маленький ребенок-сирота, которого никто не любит и не использует. В конечном счете, точный выбор контейнера зависит от вас, зависит от точной семантики, которую вы хотите выразить, и менее важна здесь, чем использовать ее в первую очередь. Как правило, программисты просто используют вектор, если у них нет особой необходимости использовать что-то еще. – Puppy

+0

Я замечаю, что размер файла multi_array все еще должен быть известен во время компиляции и, к сожалению, не работает в моем случае. В моем предыдущем комментарии я имел в виду, что размер контейнеров, который первоначально был определен, остается фиксированным на протяжении всего срока его службы. C++ 14 предлагает dynarray, но пока нет доступных реализаций. – Venom

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