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

почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. - C++

Восстановить пароль Регистрация
 
pihta
1 / 1 / 0
Регистрация: 11.11.2012
Сообщений: 23
14.09.2013, 20:58     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#ifndef SET_H
#define SET_H
 
#include <iostream>
#include <cstdlib>
 
using std::ostream;
using std::istream;
using std::endl;
using std::cerr;
using std::exit;
 
using std::cout;
 
template <typename T> class Set;
template <typename T> ostream& operator<<(ostream&, const Set<T>&);
template <typename T> istream& operator>>(istream&, Set<T>&);
 
template <typename T>
class Set
{ 
    friend ostream& operator<< <> (ostream&, const Set<T>&);
    friend istream& operator>> <> (istream&, Set<T>&);
    
    public:
        explicit Set();
        Set(const T*, int);
        
        Set(const Set&);
        ~Set();
        const Set& operator=(const Set&);
        
        int get_power() const;
        
        bool operator==(const Set&) const;
        bool operator!=(const Set&) const;
        
        const Set<T>& operator+(const Set&);
        //const Set operator^(const Set&);
        //const Set operator/(const Set&);
        
        T& operator[](int);
        T operator[](int) const;
        
    private:
        int power;
        T *begin;
};
 
template <typename T>
ostream& operator<<(ostream& output, const Set<T> &a)
{
    output << "Power: " << a.power << "; ";
    output << "Elements: ";
    for(int i=0; i<a.power; i++)
        output << a.begin[i] << " ";
    
    output << endl;
    
    return output;
}
 
template <typename T>
istream& operator>>(istream& input, Set<T> &a)
{
    int pow;
    input >> pow;
    
    a.power=(pow<0)?0:pow;
    delete [] a.begin;
    a.begin = new T[a.power];
    
    for(int i=0; i<a.power; i++)
        input >> a.begin[i];
    
    return input;
}
 
////////////////////////////////////////////////////////////////////////////////
 
template <typename T>
Set<T>::Set()
{
    power=0;
    begin=new T[power];
}
 
template <typename T>
Set<T>::Set(const T* array, int n)
{
    power=(n<0)?0:n;
 
    begin=new T[power];
    
    for(int i=0; i<power; i++)
        begin[i]=array[i];
}
 
////////////////////////////////////////////////////////////////////////////////
 
template <typename T>
Set<T>::Set(const Set &Set_to_copy)
{
    power=Set_to_copy.power;
    begin=new T[power];
    
    for(int i=0; i<power; i++)
        begin[i]=Set_to_copy.begin[i];
}
 
template <typename T>
Set<T>::~Set()
{
    delete []begin;
}
 
template <typename T>
const Set<T>& Set<T>::operator=(const Set &right)
{
    if( &right!=this )
    {
        delete []begin;
        power=right.power;
        begin=new T[power];
        
        for(int i=0; i<power; i++)
            begin[i]=right.begin[i];
    }
    
    return *this;
}
 
////////////////////////////////////////////////////////////////////////////////
 
template <typename T>
int Set<T>::get_power() const
{
    return power;
}
 
////////////////////////////////////////////////////////////////////////////////
 
template <typename T>
bool Set<T>::operator==(const Set &right) const
{
    if(power!=right.power) return false;
    
    for(int i=0; i<power; i++)
        if(begin[i]!=right.begin[i]) return false;
    
    return true;
}
 
template <typename T>
bool Set<T>::operator!=(const Set &right) const
{
    return !(*this==right);
}
 
////////////////////////////////////////////////////////////////////////////////
 
template <typename T>
const Set<T>& Set<T>::operator+(const Set<T> &right) 
{
    int pow = right.power + power;
 
    Set<T> result;
    result.power=(pow<0)?0:pow;
    delete [] result.begin;
    result.begin= new T(result.power);
    
    
    for(int i=0; i<power; i++) result.begin[i]=begin[i];
    for(int i=power; i<result.power; i++) result.begin[i]=right.begin[i-power];
    
    return result;
}
 
////////////////////////////////////////////////////////////////////////////////
        
template <typename T>
T& Set<T>::operator[](int index)
{
    if(index<0 || index>=power)
    {
        cerr << "\nError: index " << index << " out of range" << endl;
        exit(666);
    }
    
    return begin[index];
}
 
template <typename T>
T Set<T>::operator[](int index) const
{
    if(index<0 || index>=power)
    {
        cerr << "\nError: index " << index << " out of range" << endl;
        exit(666);
    }
    
    return begin[index];
}
 
////////////////////////////////////////////////////////////////////////////////
 
#endif
Вот main:
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
#include <iostream>
#include <cstdlib>
#include "set.h"
 
using std::cout;
using std::cin;
using std::endl;
 
int main()
{
    int array2[10]={15, 14, 13, 12, 11, 10, 9, 8, 7, 6};
    
    Set <int> intSet1(array2, 5);
    Set <int> intSet2(array2, 10);
    
    cout << intSet1 << endl << endl; 
    cout << intSet2 << endl << endl;
        
    cout << (intSet1+intSet2);
    
    cout << endl;
    system("pause");
    return 0;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.09.2013, 20:58     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию.
Посмотрите здесь:

Уточняющий вопрос: почему при перегрузке оператора [] необходимо возвращать ссылку? C++
Как лучше возвращать значение из операции-функции C++
C++ Почему перегруженный оператор = должен возвращать ссылку на объект
C++ Почему перегруженные шаблоны функций должны возвращать один и тот же тип?
C++ Правильно возвращать значение из функции
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
14.09.2013, 21:09     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #2
c чего вы взяли что нельзя?
можно, если сильно хочется. только нужно знать что делаете.
у вас крашится или не компилится?
вы в своем операторе возвращаете ссылку на локальную переменную, которая не существует за
пределами тела оператора +. наверно у вас все-таки краш.
SummerRain
 Аватар для SummerRain
325 / 324 / 17
Регистрация: 16.12.2012
Сообщений: 544
14.09.2013, 21:15     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #3
1)Не нужно делать operator + членом класса.
2)Вот сложили 2 + 3, возвращаете 5. 5 - это ведь не ссылка на 2 или 3, а новый объект.
pihta
1 / 1 / 0
Регистрация: 11.11.2012
Сообщений: 23
14.09.2013, 21:17  [ТС]     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #4
Не компилиться, если оставлять всё так как есть. Но если убрать амперсант в определении и реализации то крашится, и я не понимаю почему.
SummerRain
 Аватар для SummerRain
325 / 324 / 17
Регистрация: 16.12.2012
Сообщений: 544
14.09.2013, 21:22     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #5
Потому что ты возвращаешь ссылку на временный локальный объект, который разрушается, когда заканчивается тело оператора +.
И поэтому получается ссылка на удалённый объект.
Если бы ты сделал как-то так
C++
1
2
3
4
5
6
7
8
template <typename T>
const Set<T>& Set<T>::operator+(const Set<T> &right) 
{
    int pow = right.power + power;
    Set<T>* result = new Set<T>;
    //.............
    return *result;
}
Т.е. динамически выделял бы память под новый объект, в который ты записываешь результат сложения, то тогда бы краша не было.
Но это повлечет за собой утечки памяти.
pihta
1 / 1 / 0
Регистрация: 11.11.2012
Сообщений: 23
14.09.2013, 21:28  [ТС]     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #6
Хорошо. А как мне тогда сделать так, чтобы опрератор был членом класса и возвращал новый объект. Т.е. чтобы можно было сделать так:
C++
1
2
3
4
5
int main()
{
   Set o1, o2, sum;
   sum=o1+o2;
}
Добавлено через 1 минуту
Цитата Сообщение от SummerRain Посмотреть сообщение
Потому что ты возвращаешь ссылку на временный локальный объект, который разрушается, когда заканчивается тело оператора +.
И поэтому получается ссылка на удалённый объект.
Если бы ты сделал как-то так
C++
1
2
3
4
5
6
7
8
template <typename T>
const Set<T>& Set<T>::operator+(const Set<T> &right) 
{
    int pow = right.power + power;
    Set<T>* result = new Set<T>;
    //.............
    return *result;
}
Т.е. динамически выделял бы память под новый объект, в который ты записываешь результат сложения, то тогда бы краша не было.
Но это повлечет за собой утечки памяти.
Не так не идет, так плохо делать)
SummerRain
 Аватар для SummerRain
325 / 324 / 17
Регистрация: 16.12.2012
Сообщений: 544
14.09.2013, 21:32     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #7
Ну просто убери знак амперсанда.
template <typename T>
const Set<T> Set<T>::operator+(const Set<T> &right)
Твой временный объект result запишется в переменную Sum. И будет тебе счастье
pihta
1 / 1 / 0
Регистрация: 11.11.2012
Сообщений: 23
14.09.2013, 21:37  [ТС]     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #8
Да, я так пробовал, но она тогда крашится во время исполнения. Проверял с помощью cout где она перестаёт выполнятся, и у меня возникли трудности Но насколько я понял дело в "return result;"
SummerRain
 Аватар для SummerRain
325 / 324 / 17
Регистрация: 16.12.2012
Сообщений: 544
14.09.2013, 22:04     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #9
Нет не в этом дело.
А вот в чём:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T>
const Set<T> Set<T>::operator+(const Set<T> &right) 
{
    int pow = right.power + power;
    pow=(pow < 0) ? 0 : pow;
    T* result_array = new T[pow];
    
    for(int i=0; i<power; i++) result_array[i]=begin[i];
    for(int i=power; i<pow; i++) result_array[i]=right.begin[i-power];
    
    Set<T> result(result_array, pow);
    delete[] result_array;
    return result;
}
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
14.09.2013, 22:14     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #10
pihta, Те объекты которые создаются в функции они попадают в автоматическую память которая сама освобождается и ты просто возвращаешь ссылку на объект которого уже нету. (функция отработала - объекты уничтожились) Используй конструктор копирования либо попытайся выделить память оператором new а затем попробовать разыменовать указатель и применить амперсанд, ну что то типо такого сделать matrix* p=new matrix(); return &(*p); отак от объект не должен удалится (если честно я так не пробовал), вообще лучше использовать конструктор копирования, в нем все тоже самое происходит.
pihta
1 / 1 / 0
Регистрация: 11.11.2012
Сообщений: 23
14.09.2013, 22:18  [ТС]     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #11
SummerRain, Спасибо огромное, всё работает!!!
Но не можешь пояснить капельку, в чём дело, и что нужно исправить в классе?
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
14.09.2013, 22:23     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #12
Существует три вида памяти в С++ статическая - это где сохраняются глобальные объекты на все время жизни программы, автоматическая - это та память в которую попадают аргументы функции и локальные переменные которые удаляются после отработки функций в С++ есть еще ключевое слово auto для подчеркивания такой памяти и свободная память (динамическая) ее нужно самому выделять и освобождать для программы.
SummerRain
 Аватар для SummerRain
325 / 324 / 17
Регистрация: 16.12.2012
Сообщений: 544
14.09.2013, 22:25     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #13
Смотри, у тебя уже есть конструктор, который принимает массив и размер массива.
И чтобы создать новый объект, который получается при сложении, достаточно просто вычислить размер этого нового массива, выделить под него память и присвоить нужные значения его элементам.
И все: создаем новый элемент с помощью этого конструктора, как ты это уже делал в функции main()
Set <int> intSet1(array2, 5);
В теле оператора + мы тоже создаем временный объект из нового массива и его размера
Set<T> result(result_array, pow);
и возвращаем его.
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
14.09.2013, 22:31     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #14
Вообще советуют делать членами те операторы которые возвращают ссылки, все остальные операторы которые возвращают новые объект или копии нужно делать глобальными, но это так совет, можно и членом сделать.

Так Страуструп любит классы определять.


Для статической памяти ключевое слово static, подчеркивает что объект находится в статической памяти, там я забыл добавить выше.
Olivеr
 Аватар для Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
15.09.2013, 00:05     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #15
Цитата Сообщение от ninja2 Посмотреть сообщение
Существует три вида памяти в С++ статическая - это где сохраняются глобальные объекты на все время жизни программы, автоматическая - это та память в которую попадают аргументы функции и локальные переменные которые удаляются после отработки функций в С++ есть еще ключевое слово auto для подчеркивания такой памяти и свободная память (динамическая) ее нужно самому выделять и освобождать для программы.
напутал немного)
Миниатюры
почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию.   почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию.  
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.09.2013, 00:08     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию.
Еще ссылки по теме:

Почему нельзя использовать в операторе case переменные, которые определены как #define C++
C++ Почему не хочет возвращать main() ?
Почему плохо возвращать указатель из функции? C++

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

Или воспользуйтесь поиском по форуму:
Olivеr
 Аватар для Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
15.09.2013, 00:08     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию. #16
pihta, делайте так:
C++
1
2
3
4
5
6
7
8
9
friend Set operator+(const Set&, const Set&);
 
template <typename T>
Set<T> operator + (const Set<T> &lhs, const Set<T> &rhs)
{
    Set<T> result;
    // ...
    return result;
}
Yandex
Объявления
15.09.2013, 00:08     почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию.
Ответ Создать тему
Опции темы

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