Форум программистов, компьютерный форум CyberForum.ru

Возврат объекта класса из функции - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 13, средняя оценка - 4.85
random123
0 / 0 / 0
Регистрация: 14.03.2013
Сообщений: 3
14.03.2013, 19:56     Возврат объекта класса из функции #1
Имеется следующий код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include "stdafx.h"
#include <iostream>
using namespace std;
 
/*Задача:
Определить класс список элементов. В определение класса включить два конструктора для определения списка 
по его размеру и путем копирования другого списка.
Определить операции над списком:
[ ] получение значения информационного поля указанного элемента списка;
–    удаление из первого списка элементов второго, если второй список входит в первый.
*/
 
//Прототип класса
class List
{
    public:
        void Print();
        List (int);
        List (const List&);
        ~List();
        int operator [] (int);
        List operator - (List);
    private:
        int size;
        struct list
        {
            int data;
            list *next;
        };
        list *head;
};
 
 
//Конструктор, создающий список по его размеру
List::List(int sz)
{
    size=sz;
    head=NULL;
    List::list *p,*t;
    for (int i=0;i<sz;i++)
    {
        p=new List::list;
        p->data=rand()%100;
        if (head==NULL) 
        {
            head=p;
            head->data=p->data;
        }
        else {t->next=p;}
        t=p;
        p->next=NULL;
    }
}
 
//Конструктор, создающий копию существующего списка
List::List(const List& l)
{
    head=NULL;
    size=0;
    List::list *src=l.head,*p,*tl;
    while (src)
    {
        p=new List::list;
        p->data=src->data;
        p->next=NULL;
        if (head==NULL) 
        {
            head=p;
            head->data=p->data;
        }
        else {tl->next=p;}
        tl=p;
        src=src->next;
        size++;
        p->next=NULL;
    }
}
 
//Деструктор, удаляющий элементы списка
List::~List()
{
    List::list *p;
    for (int i=0;i<size;i++)
    {
        p=head;
        head=head->next;
        delete p;
    }
    cout<<"something has been destructed"<<endl;
}
 
//Функция вывода списка на экран
void List::Print()
{
    List::list *p=head;
    while(p)
    {
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}
 
//Перегрузка операции [] - возврат значения указанного элемента списка
int List::operator [] (int n)
{
    list *p=head;
    for (int i=1; (i<n)&&(p!=NULL); i++, p=p->next);
    if (p) return p->data;
    return -1;
}
 
//Перегрузка бинарного оператора "-" - удаление из первого списка элементов второго, если второй список входит в первый.
List List::operator - (List l2)
{
    List temp(0);
    cout<<"temp object created"<<endl;
    temp.head=NULL;
    temp.size=0;
    bool contains;
    list *p1=this->head,*p2=l2.head,*p=temp.head,*t=NULL;
    while (p1)
    {
        contains=false;
        cout<<"p1 data"<<p1->data<<endl;
        while (p2)
        {
            cout<<"p2 data: "<<p2->data<<endl;
            if (p1->data==p2->data) {contains=true;}
            p2=p2->next;
        }
        if (contains==false)
        {
            p=new List::list;
            p->data=p1->data;
            p->next=NULL;
            if (temp.head==NULL) 
            {
                temp.head=p;
                temp.head->data=p->data;
            }
            else {t->next=p;}
            t=p;
            temp.size++;
            cout<<endl<<"writed something into the temp object: "<<p->data<<endl;
            p=p->next;
        }
        p2=l2.head;
        cout<<"p1data"<<p1->data<<endl;
        p1=p1->next;
    }
    return temp;
}
 
//Главная функция программы
void main()
{
    int number;
    cout<<"Enter number of elements:";
    cin>>number;
    List list1(number),list2(list1),list3(0);
    cout<<endl<<"Generated list:"<<endl;
    list1.Print();
    cout<<"Copy-constructor:"<<endl;
    list2.Print();
    cout<<"Enter number of element:";
    cin>>number;
    cout<<endl<<"Element #"<<number<<" is: "<<list1[number]<<endl<<" (if = -1 -- wrong number entered)"<<endl;
    
    List list4(5);
    cout<<endl<<"Generated 4th list (contains 5 nodes):"<<endl;
    list4.Print();
 
    cout<<endl<<"Overloaded operator '-' result: list3=list1-list4"<<endl;
    list3=list1-list4;
    list3.Print();
    cout<<"main() ended"<<endl;
}
Собственно, такое впечатление, что по выходу из функции (перегруженный бинарный минус), созданный внутри объект уничтожается, и попытка запустить функцию вывода в консоль содержимого объекта вешает программу. Деструктор также не отрабатывает как положено. В чём моя ошибка? И как исправить?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
anmartex
...
 Аватар для anmartex
1700 / 1193 / 494
Регистрация: 12.02.2013
Сообщений: 1,978
15.03.2013, 09:39     Возврат объекта класса из функции #2
Замечания:
  1. Строка 19: Передавать желательно по ссылке, а не по значению. В результате передачи по значению, создаётся копия объекта, т.е. вызывается конструктор копирования.
  2. Строка 175: А вы перегружали оператор '='? Естественно нет, в этом и заключается ваша основная ошибка. Проблема в том, что результатом операции '-' вы получили временный объект, и время его жизни закончится после выполнения данной операции, что приведёт к вызову деструктора. А при отсутствии перегрузки присвоения все значения (size и head) временного объекта тупо скопируются в list3, т.е. указатель head будет указывать уже на удалённую область. А по завершению программы вызывается деструктор list3. И что по вашему он должен удалять? Кроме всего изложенного этим действием вы можете спровоцировать утечку памяти, в случае если list3 имел уже какие-либо значения. Т.е. вы должны либо перегрузить '=', либо инициализировать list3 в момент выполнения операции '-', что в свою очередь вызовет конструктор копирования.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <iostream>
#include <cstdlib>
#include <ctime>
 
using namespace std;
 
/*Задача:
Определить класс список элементов. В определение класса включить два конструктора для определения списка
по его размеру и путем копирования другого списка.
Определить операции над списком:
[ ] получение значения информационного поля указанного элемента списка;
–    удаление из первого списка элементов второго, если второй список входит в первый.
*/
 
//Прототип класса
class List
{
   public:
      void Print();
      List(int size = 0);
      List(const List&);
      ~List();
      int operator [](int);
      List operator - (const List&) const;
 
   private:
      int size;
      struct list
      {
         int data;
         list* next;
      };
      list* head;
};
 
 
//Конструктор, создающий список по его размеру
List::List(int sz): size(sz), head(NULL)
{
   List::list* t = NULL;
   for (int i = 0; i < sz; i++)
   {
      List::list* p = new List::list;
 
      p->data = rand() % 100;
      p->next = NULL;
 
      if (head == NULL)
      {
         head = p;
      }
      else
      {
         t->next = p;
      }
      t = p;
   }
}
 
//Конструктор, создающий копию существующего списка
List::List(const List& l): size(0), head(NULL)
{
   size = l.size;
 
   List::list* tl = NULL;
   for (List::list* src = l.head; src; src = src->next)
   {
      List::list* p = new List::list;
      p->data = src->data;
      p->next = NULL;
 
      if (head == NULL)
      {
         head = p;
      }
      else
      {
         tl->next = p;
      }
      tl = p;
   }
}
 
//Деструктор, удаляющий элементы списка
List::~List()
{
   while (head)
   {
      List::list* p = head;
      head = head->next;
      delete p;
   }
 
   cout << "something has been destructed" << endl;
}
 
//Функция вывода списка на экран
void List::Print()
{
   List::list* p = head;
   while (p)
   {
      cout << p->data << " ";
      p = p->next;
   }
   cout << endl;
}
 
//Перегрузка операции [] - возврат значения указанного элемента списка
int List::operator [](int n)
{
   list* p = head;
 
   for (int i = 1; (i < n) && p; ++i, p = p->next) { ; }
 
   return p ? p->data : -1;
}
 
//Перегрузка бинарного оператора "-" - удаление из первого списка элементов второго, если второй список входит в первый.
List List::operator - (const List& l2) const
{
   List temp;
   cout << "temp object created" << endl;
   bool contains;
   list* p1 = this->head, *p2 = l2.head, *p = temp.head, *t = NULL;
   while (p1)
   {
      cout << "p1 data" << p1->data << endl;
 
      contains = false;
      while (p2 && !contains)
      {
         cout << "p2 data: " << p2->data << endl;
         contains = (p1->data == p2->data);
         p2 = p2->next;
      }
 
      if (contains == false)
      {
         p = new List::list;
         p->data = p1->data;
         p->next = NULL;
         if (temp.head == NULL)
         {
            temp.head = p;
         }
         else
         {
            t->next = p;
         }
         t = p;
         temp.size++;
         cout << endl << "writed something into the temp object: " << p->data << endl;
         p = p->next;
      }
      p2 = l2.head;
      cout << "p1data" << p1->data << endl;
      p1 = p1->next;
   }
   return temp;
}
 
//Главная функция программы
int main()
{
   int number;
   cout << "Enter number of elements:";
   cin >> number;
 
   List list1(number);
   List list2(list1);
 
   cout << endl << "Generated list:" << endl;
   list1.Print();
 
   cout << "Copy-constructor:" << endl;
   list2.Print();
 
   cout << "Enter number of element:";
   cin >> number;
   cout << endl << "Element #" << number << " is: " << list1[number] << endl << " (if = -1 -- wrong number entered)" << endl;
 
   List list4(5);
   cout << endl << "Generated 4th list (contains 5 nodes):" << endl;
   list4.Print();
 
   cout << endl << "Overloaded operator '-' result: list3=list1-list4" << endl;
   List list3 = list1 - list4;
   list3.Print();
 
   cout << "main() ended" << endl;
 
   return 0;
}
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
15.03.2013, 10:38     Возврат объекта класса из функции #3
Цитата Сообщение от anmartex Посмотреть сообщение
Строка 19: Передавать желательно по ссылке, а не по значению.
Цитата Сообщение от random123 Посмотреть сообщение
List (const List&);
Так ведь и передается по ссылке.
anmartex
...
 Аватар для anmartex
1700 / 1193 / 494
Регистрация: 12.02.2013
Сообщений: 1,978
15.03.2013, 10:44     Возврат объекта класса из функции #4
Tulosba, да, верно! Блин, помню, что проблема с ссылкой была, но не то указал . Строка 114, там нет ссылки, а не в конструкторе копирования. Спасибо, что поправили.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
15.03.2013, 10:58     Возврат объекта класса из функции #5
Цитата Сообщение от anmartex Посмотреть сообщение
Строка 114, там нет ссылки
Более того, ссылка должна быть const (ведь мы не изменяем l2). И сам метод тоже должен быть const (т.к. не изменяется this).
anmartex
...
 Аватар для anmartex
1700 / 1193 / 494
Регистрация: 12.02.2013
Сообщений: 1,978
15.03.2013, 10:59     Возврат объекта класса из функции #6
Tulosba, однозначно! В моёй версии она там есть
Как я мог промазать, вообще хотел только в прототипе указать ошибку и промахнулся, вместо строки 22 указал 19
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
15.03.2013, 11:05     Возврат объекта класса из функции #7
anmartex, до кучи ещё в operator[] добавить const. Вместо NULL использовать nullptr, и вообще заменить список на std::list
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.03.2013, 11:10     Возврат объекта класса из функции
Еще ссылки по теме:

Создание объекта в функции и возврат объекта из нее C++
C++ Вызов функции с не заданными параметрами из объекта класса
C++ Виртуальная функция и возврат объекта класса

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
anmartex
...
 Аватар для anmartex
1700 / 1193 / 494
Регистрация: 12.02.2013
Сообщений: 1,978
15.03.2013, 11:10     Возврат объекта класса из функции #8
Цитата Сообщение от Tulosba Посмотреть сообщение
anmartex, до кучи ещё в operator[] добавить const. Вместо NULL использовать nullptr, и вообще заменить список на std::list
Угу
Yandex
Объявления
15.03.2013, 11:10     Возврат объекта класса из функции
Ответ Создать тему
Опции темы

Текущее время: 00:44. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru