Класс С++ с динамическим выделением памяти. Почему я получаю эту ошибку?

Я создаю класс DblArray и выполняю для него базовые функции. У меня, похоже, возникла проблема при компиляции, поскольку в нем говорится: «Неверная контрольная сумма для освобожденного объекта - объект, вероятно, был изменен после освобождения». Я опубликую весь свой код ниже, но я думаю, что проблема возникает в этой функции:

void DblArray::insertVal(double n)
{
  if ( size == capacity )
  {
    capacity *= 2;
    double temp[size];

    for ( int i = 0; i < size; i++ )
      temp[i] = data[i];
    delete [] data;
    data = 0;

    data = new double[capacity];
    for ( int i = 0; i < size; i++ )
      data[i] = temp[i];
  }
  size++;
  data[size] = n;
}

Заголовочный файл такой:

#include <iostream>

#ifndef DBLARRAY_H
#define DBLARRAY_H

class DblArray
{
private:
  long capacity;
  long size;
  double * data;
public:
  DblArray();
  ~DblArray();
  DblArray(const DblArray& d);
  DblArray& operator = (const DblArray& d);

  double operator [] (int i);
  long getCapacity();
  long getSize();
  double getAverage();
  void insertVal(double);
  void removeVal();
};

#endif // DBLARRAY_H

Файл реализации такой:

#include "DblArray.h"

DblArray::DblArray()
{
  capacity = 1;
  size = 0;
  data = new double[capacity];
}

DblArray::~DblArray()
{
  capacity = 0;
  size = 0;
  delete [] data;
  data = NULL;
}

DblArray::DblArray(const DblArray& d)
{
  capacity = d.capacity;
  size = d.size;
  data = new double[capacity];

  for ( int i = 0; i < size; i++ )
  {
    data[i] = d.data[i];
  }
}

DblArray& DblArray::operator = (const DblArray& d)
{
  DblArray dNew;
  dNew.capacity = d.capacity;
  dNew.size = d.size;
  dNew.data = new double[capacity];

  for ( int i = 0; i < dNew.size; i++ )
  {
    dNew.data[i] = d.data[i];
  }

  return dNew;
}

double DblArray::operator [] (int i)
{
  return data[i];
}

long DblArray::getCapacity()
{
  return capacity;
}

long DblArray::getSize()
{
  return size;
}

double DblArray::getAverage()
{
  double average = 0;
  for ( int i = 0; i < size; i++ )
  {
    average += data[i];
  }
  average = average / size;

  return average;
}

void DblArray::insertVal(double n)
{
  if ( size == capacity )
  {
    capacity *= 2;
    double temp[size];

    for ( int i = 0; i < size; i++ )
      temp[i] = data[i];
    delete [] data;
    data = 0;

    data = new double[capacity];
    for ( int i = 0; i < size; i++ )
      data[i] = temp[i];
  }
  size++;
  data[size] = n;
}

void DblArray::removeVal()
{
  data[size] = 0;
}

А драйвер такой:

#include <iostream>
#include "DblArray.h"

using namespace std;

DblArray print( DblArray );

int main()
{
  //Data abstractions
  DblArray d1;

  //Printing the contents of d1 before testing functions
  print(d1);

  for ( int i = 0; i < 5; i++ )
  {
    d1.insertVal(i);
  }

  //Printing contents of d1 after adding values
  print(d1);

  return 0;
}

//Function to print the contents of each object
DblArray print( DblArray d )
{
  cout << "Capacity:\t" << d.getCapacity() << endl;
  cout << "Size:\t" << d.getSize() << endl;
  cout << "Data:\t" << endl;
  for ( int i = 0; i < d.getSize(); i++ )
  {
    cout << d[i] << "\t";
  }
  cout << "\n";
}

person Ivy Blalock    schedule 26.02.2015    source источник
comment
Опубликуйте минимальный полный проверяемый пример   -  person Jonathan Mee    schedule 26.02.2015


Ответы (3)


У вас есть:

если ( размер == мощность )

затем вы выделяете:

данные = новый двойной [емкость];

поэтому данные имеют размер size. В итоге у вас есть:

размер++; данные [размер] = n;

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

person marcinj    schedule 26.02.2015

In insertVal(),

size++;
data[size] = n;

следует изменить на

data[size++] = n;

В противном случае, когда size == capacity-1, data[size] = n; записывается за границу массива. Та же проблема возникает и в removeVal().

Также семантика вашего operator=() странная. Он вообще не изменяет this, и возвращать ссылку на локальный объект неправильно. Обычно это должно выглядеть так:

DblArray& DblArray::operator=(const DblArray& rhs) {
    if (this == &rhs) return *this;
    delete [] data;
    data = new double[rhs.capacity];
    capacity = rhs.capacity;
    size = rhs.size;
    // copy rhs.data[0] .. rhs.data[size-1] into data[]
    return *this;
}

или определите DblArray::swap() и выполните идиому копирования и замены.

person timrau    schedule 26.02.2015
comment
как мне изменить operator=( )? - person Ivy Blalock; 26.02.2015
comment
Хорошо, я изменил свой оператор =(), но теперь у меня все еще есть проблемы с insertVal. Я изменил его на то, что вы сказали, потому что это определенно имеет смысл, но он все еще работает неправильно, и теперь я получаю эту ошибку: malloc: *** ошибка для объекта 0x7fff51843b80: освобождаемый указатель не был выделен - person Ivy Blalock; 26.02.2015
comment
@IvyBlalock Пожалуйста, запустите его через отладчик, чтобы увидеть, где произошла ошибка. Если этого не происходит при вставке отладочной информации, запустите ее через valgrind, чтобы увидеть, есть ли какая-либо ошибка. - person timrau; 26.02.2015

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

Функция с сигнатурой DblArray print(DblArray) не возвращает значение. Вы должны изменить подпись, чтобы она соответствовала фактическому поведению, а также рассмотреть возможность передачи DblArray в качестве ссылки: void print(const DblArray& d)

Другие проблемы, которые я обнаружил, были подняты другими ответами. Из любопытства, какой компилятор и платформу вы используете? Подумайте о том, чтобы время от времени вставлять свой код в онлайн-компилятор, gcc и clang, как правило, очень хороши с предупреждениями, если вы работаете в среде сборки Windows. В частности, я использую Coliru. Вы можете настроить флаги компилятора, чтобы отображалось больше или меньше предупреждений и т.д. В вашем примере вы сможете просто вставить все, что вы написали здесь, удалив любые директивы #include <DblArray.h>, и все готово.

person bfoster    schedule 27.02.2015