1

Эта проблема меня смутила. Первая часть кода отлично работает без сбоев, она отлично от s1 до s2. Но вторая группа кода приводит к сбою программы.проблема с перегрузкой оператора оператора

У кого-нибудь есть идеи, почему это происходит или что может быть проблема?

Код 1: (работ)

s1.add(10, 30, 25, "Test Screen", false); 
s1.add(13, 10, 5, "Name:XXX", false); 
s1.add(13, 18, 30); 
s1.remove(-1); 
Screen s2 = s1; 

Код 2: (падает на присвоение) оператор

Screen s1; 

    if (1 != s1.add(10, 30, 25, "Test Screen", false)) 
     message("first add() has a problem"); 
    else if (2 != s1.add(13, 10, 5, "Name:XXX", false)) 
     message("second add() has a problem"); 
    else if (3 != s1.add(13, 18, 30)) 
     message("third add() has a problem"); 
    else if (3 != s1.remove(-1)) 
     message("first remove() has a problem"); 
    else { 
     Screen s2 = s1; 
} 

Назначение для класса экрана:

 Screen& operator=(const Screen &scr) { 
     if (this != &scr){ 
      for (int i = 0; i < 50; i++) { 
       if (fields[i]) 
        delete fields[i]; 
       fields[i] = new LField(); 
      } 

      for (int i = 0; i < scr.numOfFields; i++) 
       fields[i] = scr.fields[i]; 

      numOfFields = scr.numOfFields; 
      currentField = scr.currentField; 
     } 
     return *this; 
    } 

Оператор присваивания для класса Field :

LField& operator=(const LField &lfieldobj) { 
     if (this != &lfieldobj) { 

      if (lfieldobj.val) { 
       if (val) 
        delete[] val; 
       val = new char[strlen(lfieldobj.val) + 1]; 
       strcpy(val, lfieldobj.val); 
      } 
      else{ 
       //val = new char[1]; 
       val = ""; 
      } 
      rowNum = lfieldobj.rowNum; 
      colNum = lfieldobj.colNum; 
      width = lfieldobj.width; 
      canEdit = lfieldobj.canEdit; 
      index = lfieldobj.index; 

     } 
     return *this; 
    } 

Любой вход был бы оценен с благодарностью :)

+2

Не видя определения оператора присваивания, на это невозможно ответить. –

+1

Вы уверены, что он сработал при задании? 's2' выйдет за рамки, как только он будет создан, так что, возможно, это проблема с деструктором? – Chowlett

+0

Я добавил уступки оператора оператора. Я уверен, что в коде, который сбой, я прокомментировал назначение, и он отлично работает. – michael

ответ

1

Что представляет собой объявление о поле?

LField* fields[50]?

Если да, то кто инициализирует элемент поля с левой стороны объекта NULL? Я бы сказал, что никто ... оператор присваивания не похож на конструктор копирования на C++, и вы вызываете delete с недопустимым указателем.

0

Мне удалось его исправить. Это была проблема с распределением памяти в конце концов :)

+1

Это может быть, но ваш код ** не ** вызывает оператор присваивания вообще. Ошибка в вашем конструкторе копирования - вам тоже нужно исправить это. –

+1

и избавиться от каждого нового и удалить, как предложил Джерри –

2

Избавьтесь от своего текущего val и замените его на std::string. Избавьтесь от своего fields и замените его на std::vector. Это должно позволить вам устранить как ваших перегруженных операторов присваивания; компилятор предоставит те, которые работают. Думаю, вы устраните проблемы управления памятью вместе с кодом.

Поскольку он стоит прямо сейчас, даже если вы «исправите» проблемы (задачи) управления памятью, о которых вы знаете, вы останетесь с тем, что ваш код полностью небезопасен перед исключениями (и использует new, поэтому он в принципе не может избежать исключений).

2
 for (int i = 0; i < scr.numOfFields; i++) 
      fields[i] = scr.fields[i]; 

Это не нормально, вы копируете указатель вместо указательного значения. Требуется глубокая копия.

1

Линия

Screen s2 = s1; 

на самом деле вызывает конструктор Screen копирования, а не перегрузки оператора присваивания.

Например:

#include <iostream> 
using namespace std; 

class Screen 
{ 
public: 
     Screen() { } 

     Screen(const Screen& s) 
     { 
       cout << "in `Screen::Screen(const Screen&)`" << endl; 
     } 

     Screen& operator=(const Screen& s) 
     { 
       cout << "in `Screen::operator=(const Screen&)`" << endl; 
       return *this; 
     } 
}; 

int main() 
{ 
     Screen s1; 
     Screen s2 = s1; 
} 

печатает:

в Screen::Screen(const Screen&)

Я предполагаю, что ваш Screen конструктор копирования определен похож на Screen::operator=(const Screen&), поэтому исправление для может потребоваться также применение перегрузки оператора-оператора для определения конструктора копирования.

Также как определяется fields член Screen? Если это так:

LField* fields[50]; 

затем в конструкторах, вы должны инициализировать все LField* объекты в массиве NULL, поскольку они имеют неопределенные начальные значения:

std::fill_n(fields, 50, static_cast<LField*>(NULL)); 

Без такой инициализации тест if (fields[i]) может преуспеть для некоторого i, хотя fields[i] не указывает на выделение, в результате чего ваша программа пытается указать delete указатель (и), которые не были возвращены new.

0

Для сложных объектов лучше использовать копировать и обменивать idum.
Это дает вам оператор присваивания с исключительным гарантом исключения (транзакционный сейф). Но это также означает, что вам нужно только рассмотреть сложное создание объекта в одном месте (конструкторы).

Screen& Screen::operator=(Screen const& rhs) 
{ 
    Screen tmp(rhs); 
    this->swap(tmp); 
    return *this; 
} 

void Screen::swap(Screen const& rhs) throw() 
{ 
    // Swap each of the members for this with rhs. 
    // Use the same pattern for Field. 
} 
Смежные вопросы