Программа C ++ пытается удвоить пользовательский объект dealloc

0

Для будущих посетителей

Оказывается, у меня не было оператора присваивания копий, определенного в моем пользовательском классе, и поэтому компилятор по умолчанию "копировал поведение указателя объекта".

Если вы смущены тем, что такое оператор присваивания копий, как и я, этот ресурс может помочь вам разобраться, как выглядит "оператор присваивания копий" в C++.

Ниже приведено исходное задание. (Ссылки на исходный код истекают через месяц, извините!)


Я работаю над консольным приложением, которое имитирует книжный магазин, но продолжайте получать сообщение об ошибке _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) в моей программе во время выполнения. После некоторого поиска (и некоторой отрывочной отладки) я пришел к выводу, что мой деструктор объекта вызывается дважды. Я надеюсь, что нижеприведенные фрагменты кода сделают это немного яснее, что я имею в виду. (Нажатие на имена файлов откроет пасты с соответствующим кодом для упрощения чтения/декларации.)


bookdata.h

#ifndef BOOKDATA_H
#define BOOKDATA_H

class bookData {
  private:
    char* bookTitle;
    char* isbn;
    char* author;
    char* publisher;
    char* dateAdded;
    int qtyOnHand;
    double wholesale;
    double retail;

  public:
    bookData();
    bookData(char* title, char* isbn, char* author, char* publisher, char* date, int qty, double wholesale, double retail);
    bookData(bookData& book); // Meant to be called during memberwise assignment
    ~bookData();

    // Various setter & getter funcs
};

#endif

bookData.cpp

#include "globals.h"
#include "bookData.h"

using namespace std;

// Variables in caps are const ints defined in globals.h 

bookData::bookData() {
  bookTitle = new char[TITLE_LENGTH];
  isbn = new char[ISBN_LENGTH];
  author = new char[AUTHOR_LENGTH];
  publisher = new char[PUBLISHER_LENGTH];
  dateAdded = new char[DATE_LENGTH];
  qtyOnHand = 0;
  wholesale = 0;
  retail = 0;

  char emptyTitle[2];
  emptyTitle[0] = '\0';
  setTitle(emptyTitle);
}

// Other constructors are overloaded version of bookData & copy data;
// See example setter function below destructor

bookData::~bookData() {
  if (bookTitle)
    delete [] bookTitle;
  else
    return;
  delete [] isbn;
  delete [] author;
  delete [] publisher;
  delete [] dateAdded;
}

// Setter functions are of this form (excl. ints & doubles)
void bookData::setTitle(const char* input) {
  for (int len = 0; len < TITLE_LENGTH - 1; len++) {
    *(bookTitle + len) = *(input + len);
    if (*(input + len) == '\0')
      break;
    else if (len == TITLE_LENGTH - 2)
      *(bookTitle + ++len) = '\0';
  }
}

// Getter functions are of this form (excl. ints & doubles)
const char* bookData::getTitle() { return bookTitle; }

reports.cpp (файл, дважды вызывающий деструктор)

void repQty() {

  // Again, variables in all caps are defined in globals.h if you don't see 
  // their declaration
  bookData bookArray[MAX_RECORDS];

  // Global function which populates bookArray from a datafile
  bookData* books = getBooks(bookArray);

  // Some code to find the memory address of the first and last book in the records
  bookData* HEAD = books;
  // Keep advancing until books no longer points to a non-empty bookData object
  // "Empty" defined as book bookTitle variable starting with '\0'
  bookData* TAIL = --books;

  // Need all 3 pointers for a naive, in place insertion/linear sort routine
  // Outputs book data following the sort

  // Before returning, calls the destructors for the books in bookArray
  // Also calls the destructor for books, HEAD, and TAIL as well
  // ...which were already called as part of the bookArray destructor calls
  // Which is where I have my problem now
}

Бонус: globals.h

Как вы могли заметить, я уже попытался проверить, был ли объект bookData уже удален, используя if (bookTitle) в функции деструктора, но он по-прежнему оценивается как истинный, когда я запускаю его через VS Step Into. Если не считать деструктора все вместе, что я могу сделать, чтобы обойти эту проблему и заставить деструктор преждевременно выйти, если объект, о котором идет речь, уже освобожден?

  • 0
    Я чувствую, что должен добавить, что я уже искал и нашел ответы в духе «оператор delete только изменяет bookTitle памяти bookTitle на случайный», а затем настоятельно рекомендую не устанавливать вручную новый адрес памяти bookTitle в NULL Я в растерянности из-за того, что мне следует делать - я уже искал 2-3 часа и не могу понять.
  • 0
    Если поток управления входит в деструктор уже уничтоженного объекта, уже немного поздно что-либо делать с этим. Вы должны убедиться, что этого не произойдет.
Показать ещё 8 комментариев
Теги:

1 ответ

1
Лучший ответ

Я уже пытался проверить, был ли объект bookData уже удален, используя if (bookTitle) в функции деструктора

Поскольку delete[] не устанавливает указатель на NULL, проверка фактически является no-op.

Даже если вы указали указатель на NULL вручную, вы должны устранить симптомы проблемы, а не основную причину.

Основная причина заключается в том, что вы не выполняете оператор присваивания копий, тем самым нарушая правило из трех. Случается, что вы используете неявно сгенерированный оператор присваивания копии:

  swap = *books;
  *books = *(books - 1);
  *(books - 1) = swap;

и этот оператор не делает правильные вещи: он копирует указатели вместо копирования данных. Прямым следствием этого являются двойные удаления.

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

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

  • 0
    Вы ответили так же, как я разместил комментарий, адресованный этому . Я просто не могу придумать другого пути, поскольку Vis Studio показывает, что адрес данных был изменен при отладке.
  • 0
    Полный код конструктора копирования можно найти здесь , но я не думаю, что он глючит. Кроме того, я уже видел Правило трех, упомянутое уже несколько раз, но я не уверен, что мне не хватает - похоже, это оператор присваивания копии, но я не совсем понимаю, что это такое.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню