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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
pihta
1 / 1 / 0
Регистрация: 11.11.2012
Сообщений: 23
#1

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

14.09.2013, 20:58. Просмотров 540. Ответов 15
Метки нет (Все метки)

Второй час сижу над одним и тем же кодом и не могу понять, что не так. Не могу сообразить почему нельзя в операторе + возвращать оригинальное значение(по ссылке), а не копию.

Вот шаблон класса "множество":
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++):

Почему нельзя использовать в операторе case переменные, которые определены как #define - C++
Я не понимаю, почему Visual Studio ругается на строку с case в коде. Вроде все правильно. Если там написать напрямую цифру, тогда все...

Можно ли получить копию объекта по ссылке? - C++
Добрый день. Столкнулся со следующей проблемой: В интерфейсе функции есть такое объявление метода class Logger : public ILogger ...

Почему не хочет возвращать main() ? - C++
Вот практикуюсь в C++, а тут return main(); не хочет работать - красным main() подчёркивает. Почему здесь ошибка, подскажите пожалуйста. ...

Почему не срабатывают условия в операторе if (работа с массивами)? - C++
Приветствую. Есть код: #include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;clocale&gt; using namespace std; int main() { float...

Почему плохо возвращать указатель из функции? - C++
Почему плохо то, что мы возвращаем указатель?(return rez) #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #define SIZE 10 int*...

Получить оригинальное имя файла по ссылке - PHP
Есть сайт с ссылками на файлы, но в ссылках указан не настоящий путь (напр http://site.ru/filename.doc) а переделанный (напр...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
DU
1483 / 1059 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
14.09.2013, 21:09 #2
c чего вы взяли что нельзя?
можно, если сильно хочется. только нужно знать что делаете.
у вас крашится или не компилится?
вы в своем операторе возвращаете ссылку на локальную переменную, которая не существует за
пределами тела оператора +. наверно у вас все-таки краш.
SummerRain
326 / 325 / 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
326 / 325 / 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
326 / 325 / 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
326 / 325 / 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
231 / 187 / 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
231 / 187 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
14.09.2013, 22:23 #12
Существует три вида памяти в С++ статическая - это где сохраняются глобальные объекты на все время жизни программы, автоматическая - это та память в которую попадают аргументы функции и локальные переменные которые удаляются после отработки функций в С++ есть еще ключевое слово auto для подчеркивания такой памяти и свободная память (динамическая) ее нужно самому выделять и освобождать для программы.
SummerRain
326 / 325 / 17
Регистрация: 16.12.2012
Сообщений: 544
14.09.2013, 22:25 #13
Смотри, у тебя уже есть конструктор, который принимает массив и размер массива.
И чтобы создать новый объект, который получается при сложении, достаточно просто вычислить размер этого нового массива, выделить под него память и присвоить нужные значения его элементам.
И все: создаем новый элемент с помощью этого конструктора, как ты это уже делал в функции main()
Set <int> intSet1(array2, 5);
В теле оператора + мы тоже создаем временный объект из нового массива и его размера
Set<T> result(result_array, pow);
и возвращаем его.
ninja2
231 / 187 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
14.09.2013, 22:31 #14
Вообще советуют делать членами те операторы которые возвращают ссылки, все остальные операторы которые возвращают новые объект или копии нужно делать глобальными, но это так совет, можно и членом сделать.

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


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

Почему нельзя заменить значение - HTML, CSS
h1 { color:#A83001; font-size:36px; border-bottom:1px solid #741D00; margin-bottom: 10px; ...

создать класс способный возвращать копию самого себя - C#
Надо создать класс способный возвращать копию самого себя, за счет применения метода GetCopy, который должен использовать метод...

Почему нельзя передать тип-значение в lock - C#
Всем привет. Прочитал немало статей про конструкцию lock, но все равно остался несовсем понятный момент, который собственно и записан в...

Почему нельзя присвоить значение символу внутри строки - C#
Чтобы получить значение отдельного символа строки, достаточно использовать индекс. Например: string str = &quot; t e s t &quot; ; ...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
15.09.2013, 00:05
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru