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

Передача параметра по ссылке - C++

Восстановить пароль Регистрация
 
moskitos80
 Аватар для moskitos80
39 / 39 / 0
Регистрация: 04.10.2011
Сообщений: 128
13.09.2012, 13:51     Передача параметра по ссылке #1
Всем здравствуйте. Други, помогите разобраться.
Сидю вникаю в работу указателей и памяти, паралельно пытаюсь написать велосипед, в виде контейнера аля вектор. После хочу сваять из него темплейт и перегрузить оператор [] и т.п. , а пока он имеет такой вид, как я представил. Вот примерная схема организации данных:

Передача параметра по ссылке


Здесь класс MsqArr имеет поле MsqData* dataPtr - массив указателей на структуры, которые содержат число - индекс, и указатель на данные, позже все действия по сортировке и перестановке будут производиться с массивом указателей на структуры.

Так вот вопрос, ниже в коде, в методе:
MsqArr::insert(const int idx, const int &val)

- если передать параметр val не по ссылке, а по значению:
MsqArr::insert(const int idx, const int val)

то после, когда я вызываю этот метод сколько то раз, что бы задать пары индекс - значение, и вывожу на экран... Вуаля - все элементы почему - то имеют одно и тоже значение - то которое передавалось последнему вызову, хотя значения индексов имеют нужные значения. Не подскажите почему?

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
#include <iostream>
 
using namespace std;
 
///////////////////////////////////////////////////////////
struct MsqData {
    int index;
    const int* data;
};
///////////////////////////////////////////////////////////
class MsqArr {
 
    public :
 
        MsqArr() :
            length (0),
            dataPtr(NULL)
        {}
 
        ~MsqArr()
        {
            delete [] this->dataPtr;
        }
        // Вот сдесь если второй параметр передавать не по ссылке
        // то все элементы будут иметь одно и то же значение - последнее.
        // @param int idx - индекс элемента
        // @param int val - значение элемента
        bool insert(const int idx, const int val)
        {
            MsqData *ptrArr = new MsqData[this->length + 1];
 
            for (int i = 0; i < this->length; i++) {
                *(ptrArr + i) = *(this->dataPtr + i);
                delete (this->dataPtr + i);
            }
 
            this->dataPtr = ptrArr;
 
            (this->dataPtr + this->length)->index = idx;
            (this->dataPtr + this->length)->data  =& val;
 
            this->length++;
            return true;
        }
 
        friend ostream& operator << (ostream& out, MsqArr& arr)
        {
            cout << "Array(" << endl;
            for (int i = 0; i < arr.length; i++) {
                cout << "\t[" << (arr.dataPtr + i)->index << "] => "
                     << *((arr.dataPtr + i)->data) << endl;
            }
            cout << ")" << endl;
            return out;
        }
 
    protected :
        int length;
        MsqData* dataPtr;
};
///////////////////////////////////////////////////////////
int main()
{
    MsqArr arr1;
 
    try {
 
        arr1.insert(0, 111);
        arr1.insert(1, 222);
        arr1.insert(2, 333);
        arr1.insert(3, 444);
 
    } catch (bad_alloc) {
        cout << "Bad allocation memory!" << endl;
    }
 
    cout << arr1 << endl;
 
    return 0;
}
ЗЫ: Я конечно понимаю, что, передав параметр по значению, переменная val - в методе становится локальной и погибает по окончанию работы с методом, а указатель (this->dataPtr + ... )->data указывает хрензнаеткуда, но почему в итоге вывод имеет следующий вид:

// если передавать НЕ по ссылке то таким (парадокс):
Array(
[0] => 444
[1] => 444
[2] => 444
[3] => 444
)

// если передавть параметр по ссылке, то вывод проги будет следующим (то что нужно):
Array(
[0] => 111
[1] => 222
[2] => 333
[3] => 444
)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.09.2012, 13:51     Передача параметра по ссылке
Посмотрите здесь:

C++ Передача по ссылке
Передача значения по ссылке C++
Передача структуры по ссылке C++
C++ Передача значения по ссылке
C++ Передача по ссылке
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
13.09.2012, 14:08     Передача параметра по ссылке #2
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 bool insert(const int idx, const int val)
        {
            MsqData *ptrArr = new MsqData[length + 1];
 
            for (int i = 0; i < length; i++) {
                *(ptrArr + i) = *(this->dataPtr + i);
                //delete (this->dataPtr + i);//с этим у меня не работало
            }
            if(dataPtr)delete[] dataPtr;
            this->dataPtr = ptrArr;
 
            (this->dataPtr + this->length)->index = idx;
            (this->dataPtr + this->length)->data  = new int(val);
 
            this->length++;
            return true;
        }
И зачем везде this? так обычно не пишут... вам компилятор не жалуется на old-style?

Добавлено через 6 минут
Цитата Сообщение от moskitos80 Посмотреть сообщение
Вуаля - все элементы почему - то имеют одно и тоже значение
Я так понимаю, они пушаются в стек на одно и то же место. Попробуйте сделать cout << &val и увидите, что адрес один и тот же
Герц
523 / 340 / 4
Регистрация: 05.11.2010
Сообщений: 1,077
Записей в блоге: 1
13.09.2012, 14:09     Передача параметра по ссылке #3
Почему это не пишут? Пишут.
Нужно же различать в коде поля класса и прочие переменные, вот и пишут везде this->field.
Хотя лучше давать полям какой-нибудь префикс, например 'mField' или 'm_field'
moskitos80
 Аватар для moskitos80
39 / 39 / 0
Регистрация: 04.10.2011
Сообщений: 128
13.09.2012, 17:20  [ТС]     Передача параметра по ссылке #4
Цитата Сообщение от Герц Посмотреть сообщение
Нужно же различать в коде поля класса и прочие переменные
Именно по этой причине всегда пишу this->...

Цитата Сообщение от I.M. Посмотреть сообщение
(this->dataPtr + this->length)->data *= new int(val);
!!! Вот спасибо добрый человече! Теперь, кстати я могу передавать в метод константы.

Добавлено через 46 минут
Посмотрите пожалуйста, что у меня в результате получилось... как вы думаете это полное убожество или более - менее нормальная реализация? Если можно укажите пожалуйста мои ошибки. Я С++ изучаю около 3 месяцев, самостоятельно, по книге Р.Лафоре: "ООП в С++" хотелось бы знать мнение сведущего человека:

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
#include <iostream>
#include <string>
 
using namespace std;
 
namespace msq {
///////////////////////////////////////////////////////////
template<class Type>
struct MsqData {
    int index;
    Type* data;
};
///////////////////////////////////////////////////////////
template<class Type>
class Array {
 
    public :
        Array() :
            length (0),
            dataPtr(NULL)
        {/*empty*/}
 
        ~Array()
        {
            delete [] this->dataPtr;// В АД!
        }
        /** Создать элемент под индексом idx со значением val
         * @param const int idx - индекс элемента
         * @param const int val - значение элемента
         * @return void
         */
        void set(const int idx, const Type &val)
        {
            // Если такой индекс у нас уже существует,
            // Мы просто перезапишем его значение:
            if (this->isset(idx)) {
                (this->dataPtr + idx)->index = idx;
                (this->dataPtr + idx)->data  = new Type(val);
                return;
            }
            // Создаём новый массив кол-вом элементов на 1
            // больше существующего this->dataPtr, что бы
            // поместить туды новый элемент:
            MsqData<Type> *ptrArr = new MsqData<Type>[this->length + 1];
            // Перегоняем указатели в новый массив
            // после цикла у нас останется не заполненным
            // последний элемент:
            for (int i = 0; i < this->length; i++) {
                *(ptrArr + i) = *(this->dataPtr + i);
                delete (this->dataPtr + i);
            }
            // Меняем назначение указателя на массив новой
            // размерности:
            this->dataPtr = ptrArr;
            // Заполняем последний элемент новым значениями
            (this->dataPtr + this->length)->index = idx;
            (this->dataPtr + this->length)->data  = new Type(val);
            // Инкрементируем длину нашего массива
            this->length++;
            return;
        }
        /** Получить элемент под индексом idx
         *  если такого элемента не существует вернёт 0
         * @param const int idx - индекс элемента
         * @return int&
         */
        Type& get(int idx)
        {
            // Если такой индекс есть - возвращаем значение
            // Здесь не получается сделать так:
            // if (this->isset(idx)) . . .
            // потому что Array::isset(int idx) - вернет тип bool
            for (int i = 0; i < this->length; i++) {
                if ( (this->dataPtr + i)->index == idx ) {
                    return *(this->dataPtr + i)->data;
                }
            }
            // Если нет возвращаем тип инициализированный нулём
            return *(new Type);
        }
        /** Проверить, существует ли элемент под индексом idx
         *  если такого элемента не существует вернёт false
         * @param const int idx - индекс элемента
         * @return bool
         */
        bool isset(const int idx)
        {
            for (int i = 0; i < this->length; i++) {
                if ( (this->dataPtr + i)->index == idx ) {
                    return true;
                }
            }
            return false;
        }
 
        Type& operator [] (const int idx)
        {
            // Если такого индекса не существует...
            if (!this->isset(idx)) {
                // Заводим его с пустым значением
                this->set(idx, *(new Type));
            }
            return this->get(idx);
        }
 
        friend ostream& operator << (ostream& out, Array<Type>& arr)
        {
            cout << "Array(" << endl;
            for (int i = 0; i < arr.length; i++) {
                cout << "\t["  << (arr.dataPtr + i)->index << "] => "
                     << arr[i] << endl;
            }
            cout << ")" << endl;
            return out;
        }
 
    protected :
        // Длина массива
        int length;
        // Массив указателей на структуры с индексами и указателями
        MsqData<Type>* dataPtr;
};
///////////////////////////////////////////////////////////
} // END namespace msq
 
int main()
{
    // TESTING:
    
    msq::Array<int>    intArray;
    msq::Array<string> stringArray;
    msq::Array<double> doubleArray;
 
    cout << "----------------- INT --------------" << endl;
 
    intArray[0] = 555;
    intArray[1] = 777;
 
    cout << intArray << endl;
    cout << "intArray[0]  = " << intArray[0]  << endl;
    cout << "intArray[1]  = " << intArray[1]  << endl;
    cout << "intArray[50] = " << intArray[50] << endl;// Не существующий!
 
    cout << "-------------------------------------" << endl;
 
    cout << "---------------- DOUBLE -------------" << endl;
 
    doubleArray[0] = 111.5;
    doubleArray[1] = 222.5;
 
    cout << doubleArray << endl;
    cout << "doubleArray[0]  = " << doubleArray[0]  << endl;
    cout << "doubleArray[1]  = " << doubleArray[1]  << endl;
    cout << "doubleArray[50] = " << doubleArray[50] << endl;// Не существующий!
 
    cout << "-------------------------------------" << endl;
 
    cout << "---------------- STRING -------------" << endl;
 
    stringArray[0] = "one";
    stringArray[1] = "two";
 
    cout << stringArray << endl;
    cout << "stringArray[0]  = " << stringArray[0]  << endl;
    cout << "stringArray[1]  = " << stringArray[1]  << endl;
    cout << "stringArray[50] = " << stringArray[50] << endl;// Не существующий!
 
    cout << "-------------------------------------" << endl;
 
    return 0;
}
Yandex
Объявления
13.09.2012, 17:20     Передача параметра по ссылке
Ответ Создать тему
Опции темы

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