Управление памятью
|
|
catstail | Дата: Понедельник, 30.03.2020, 17:05 | Сообщение # 1 |
Рядовой
Группа: Пользователи
Сообщений: 7
Статус: Offline
| Предположим, определен тип
Код Type My i as integer End type
Могу ли я вернуть объект типа My из функции:
Код Function f(...) as My Dim a as My ... return a End Function
В VB это возможно. Можно и динамический массив так вернуть. А как обстоит дело во FB? Сохранится ли a после возврата? В какой памяти создастся a (в стеке, в куче)?
|
|
| |
haav | Дата: Понедельник, 30.03.2020, 21:07 | Сообщение # 2 |
Генералиссимус
Группа: Администраторы
Сообщений: 1374
Статус: Offline
| Цитата catstail ( ) В VB это возможно. Можно и динамический массив так вернуть. А как обстоит дело во FB? Сохранится ли a после возврата? Я бы не стал на такое полагаться в FB.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
catstail | Дата: Понедельник, 30.03.2020, 21:58 | Сообщение # 3 |
Рядовой
Группа: Пользователи
Сообщений: 7
Статус: Offline
| Предположим, я делаю свой класс и хочу перегрузить +. На входе функции-оператора два объекта l и r. В теле оператора я создаю новый объект и должен его вернуть. Как это в таком случае сделать? Добавлено (30.03.2020, 22:13) --------------------------------------------- Вот пример из документации по FB:
Код Type rational '' Простой тип rational numerator As Integer denominator As Integer End Type
'' Умножает два рациональных типа Function rational_multiply( r1 As rational, r2 As rational ) As rational
Dim r As rational '' умножить делители ... r.numerator = r1.numerator * r2.numerator r.denominator = r1.denominator * r2.denominator
'' ... и вернуть результат Return r
End Function
Он правильный?
|
|
| |
haav | Дата: Вторник, 31.03.2020, 09:43 | Сообщение # 4 |
Генералиссимус
Группа: Администраторы
Сообщений: 1374
Статус: Offline
| catstail , когда я писал:
Код Я бы не стал на такое полагаться в FB.
я писал про возвращение динамического массива (его значения в теории являются локальными). Это не означает , что значения массива в обязательном порядке затрутся... Однако на мой взгляд правильнее объявить массив в основном коде и передать его в параметре функции:
Код redim iDM(5) as Long ' объявим динамический массив нулевой длины sub F( iM() as Long ) redim iM(10) as Long ' переобъявление массива for i as Long = 0 to 10 iM(i) = i Next End Sub f( iDM() ) for i as Long = 0 to ubound(iDM) ? iDM(i) Next sleep
С объектами все должно быть нормально, иначе они не имеют смысла в той редакции, которую предоставляют разработчики. И да пример из справки в теории правильный.
Я же всегда стараюсь придерживаться практики указателей , которая дает полный контроль над кодом:
Код type rational numerator As Integer denominator As Integer End Type declare operator +( r1 As rational, r2 As rational) As rational ptr operator + ( r1 As rational, r2 As rational) As rational ptr Dim r As rational ptr = new rational if r then r->numerator = r1.numerator + r2.numerator r->denominator = r1.denominator + r2.denominator EndIf Return r End operator dim as rational ptr tR = new rational (100,200) , tL = new rational (300,400) , tResult if tR andalso tL then tResult = *tR + *tL delete tR delete tL EndIf if tResult then ? tResult->numerator , tResult->denominator delete tResult EndIf sleep
Главное, что такие объекты живы пока я этого хочу , в отличии от статических объектов , которые будут висеть до конца работы программы.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
haav | Дата: Вторник, 31.03.2020, 11:13 | Сообщение # 5 |
Генералиссимус
Группа: Администраторы
Сообщений: 1374
Статус: Offline
| Цитата В какой памяти создастся a (в стеке, в куче)?
В стеке конечно , это ведь локальная переменная. Точно так же и любая переменная основного кода FB (кроме Static , Shared) тоже лежит в стеке. Основной код FB - это по сути функция "MAIN" Нам ведь важно не то, где хранятся , а то: сохраняются ли данные возвращаемого объекта после работы функции и являются ли они валидными для дальнейшей работы с ними. Так?
Давай возьмем простую программу:
Код Type My i as integer s as zstring*100 s1 as zstring*100 s2 as zstring*100 End type
Function f() as My Dim a as My a.i = 98 a.s = "111111" a.s1 = "2222222" a.s2 = "3333333" return a End Function
asm int 3 dim k as MY = f()
? k.i ? K.s ? k.s1 ? k.s2 sleep
посмотрим на асм код небольшой части программы:
адрес: 4019ed - это по сути место вызова нашей функции f(). Смотрим , что после вызова. А там два адреса забиваются в регистры RDI и RSI. Дальше идет операция копирования и мы видим , что по адресу rbp-0x190 (по сути объект "k") после копирования лежит копия данных объекта "а":
дамп стека (rbp-0x190) после операции копирования:
Вывод: объект "k" является частью функции "MAIN" , а раз так , то является таким же долгожителем как и любая переменная, объявленная в основном коде (то есть до конца работы программы). Объект "а" является локальной переменной функции "F" , а значит живет только до выхода из функции "F". Данные объекта "а" успешно копируются в объект "k" и ими можно без опасения пользоваться. Однако следует не забывать , что стек конечен , поэтому увлекаться большим кол-вом таких объектов , а особенно объектов с большим размером не стоит. Именно поэтому я придерживаюсь практики указателей.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
catstail | Дата: Среда, 01.04.2020, 14:35 | Сообщение # 6 |
Рядовой
Группа: Пользователи
Сообщений: 7
Статус: Offline
| Огромное спасибо за развернутый ответ. Но как пример из справки может быть правильным, если объект создается в стеке?
Взгляните на код:
Код Type rational '' Простой тип rational numerator As Integer denominator As Integer Declare Constructor(n As Integer, d As Integer) Declare Constructor() Declare Destructor() Declare Function toString() As String End Type
Constructor rational(n As Integer, d As Integer) this.numerator=n this.denominator=d Print "created: ";Str(n);" ";Str(d);" ";@This End Constructor
Constructor rational() this.numerator=0 this.denominator=1 Print "*created: ";Str(0);" ";Str(1);" ";@This End Constructor
Destructor rational() Print "destroyed ";@This End Destructor
Function rational.toString() As String Return Str(this.numerator)+"/"+Str(this.denominator) End Function
'' Умножает два рациональных типа Function rational_multiply( r1 As rational, r2 As rational ) As rational Print "enter mult" Dim r As rational '' умножить делители ... r.numerator = r1.numerator * r2.numerator r.denominator = r1.denominator * r2.denominator '' ... и вернуть результат Print "exit mult" Return r
End Function
Sub main() Dim r1 As rational=Rational(1,2) Dim r2 As rational=Rational(1,3) Dim r3 As rational'=rational_multiply(r1,r2) r3=rational_multiply(r1,r2) Print r3.toString() Sleep End Sub
main() sleep
Когда он отрабатывает, получается следующий протокол:
created: 1 2 1375876 created: 1 3 1375868 *created: 0 1 1375860 enter mult *created: 0 1 1375824 exit mult destroyed 1375824 destroyed 1375852 '!!! 1/6 destroyed 1375860 destroyed 1375868 destroyed 1375876
Видно, что имеет место "лишний" вызов деструктора (помечен !!!). Такое впечатление, что имеет место неявный вызов конструктора копирования (они есть у FB?)
Что же касается использования new (и указателей), то суть-то понятна, но немного неудобно, что придется везде использовать разыменование...
|
|
| |
haav | Дата: Среда, 01.04.2020, 18:40 | Сообщение # 7 |
Генералиссимус
Группа: Администраторы
Сообщений: 1374
Статус: Offline
| Кстати давай сразу на "ТЫ."
Далее давай определим, что представляют мои знания об ООП:
Я пользуюсь некоторыми простейшими фичами ооп и то только в тех случаях , когда это значительно помогает в реализации, упрощает код и понимание кода. То есть ООП для меня не смысл жизни и далеко не обязательный критерий кодинга. Однако я могу порекомендовать задавать вопросы про ООП на оф. форуме , там есть (как мне кажется) гуру в этом вопросе, зовут fxm. На форуме он бывает ежедневно и представляет из себя очень отзывчивого человека. Я думаю , что во всем , что касается знаний о синтаксисе FB - он лучший! Мои знания в вопросе ООП крайне ограничены.
Теперь по поводу вопроса:
Цитата catstail ( ) Но как пример из справки может быть правильным, если объект создается в стеке?
Изначально вопрос был задан по этому примеру: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgReturn Где я не прав, ответив что он правильный? Пример работает как задумано. В нем нет конструкторов , деструкторов , это уже ты сам пририсовал позднее. И кстати, зачем столько кода , если ты хотел показать сомнительность работы программы? Вот в принципе данного куска кода было бы достаточно:
Код Type rational numerator As Integer denominator As Integer Declare Constructor() Declare Destructor() End Type
Constructor rational() Print "*created: "; @This End Constructor
Destructor rational() Print "destroyed ";@This End Destructor
Function rational_multiply( ) As rational Dim r As rational Return r End Function
rational_multiply() sleep
И тебе понятнее и людям легче вникнуть в суть вопроса. Мне кстати интересно как стек может мешать принципам правильности данного примера? То что он работает криво , вызывая лишний раз деструктор , это я понимаю (наверное это баг, кстати размещу на оф. форуме данный код , может пофиксят или меня поправят ) , но твое утверждение как бы говорит о том , что подобная реализация в принципе не может размещать объекты в стеке. Я правильно понял ? Если да, то почему ты так считаешь?
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
haav | Дата: Среда, 01.04.2020, 18:46 | Сообщение # 8 |
Генералиссимус
Группа: Администраторы
Сообщений: 1374
Статус: Offline
| Цитата Такое впечатление, что имеет место неявный вызов конструктора копирования (они есть у FB?) Да, забыл про этот вопрос... Это считается конструктором копирования? :
Код Type Child Dim As long i Declare Constructor () Declare Constructor (Byref As Child) End Type
Constructor Child() i = 100 ? @this End Constructor
Constructor Child(Byref p As Child) ? @this this.i = p.i End Constructor
Dim As Child c1 Dim As Child c2 = c1
sleep
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
catstail | Дата: Среда, 01.04.2020, 18:51 | Сообщение # 9 |
Рядовой
Группа: Пользователи
Сообщений: 7
Статус: Offline
| Ок. Я беспокоюсь вот о чем. Если некий объект создается в стеке, а потом ссылка на него возвращается из функции, то память, в которой расположен объект, может быть затерта при вызове другой функции. В C/C++ так нельзя. А в VB можно. Но в VB менеджер памяти (как в Java), это очень расслабляет.
Мое отношение к ООП аналогично. Но, вообще-то, это вещь удобная. Поэтому пренебрегать не стоит.
По поводу бага... Есть подозрение, что имеет место теневой вызов конструктора копирования. В C++ я с этим сталкивался. Позже приведу код на C++. Решил заняться FB, т.к. появилось желание делать приложения, независимые от Microsoft. FB, как мне кажется, для этого идеально подходит. Но требует привычки. Что я и вырабатываю.
|
|
| |
bxusinboy | Дата: Среда, 01.04.2020, 19:05 | Сообщение # 10 |
Рядовой
Группа: Пользователи
Сообщений: 16
Статус: Offline
| Вот это скрытый конструктор: Код Type rational '' Простой тип rational numerator As Integer denominator As Integer Declare Constructor(n As Integer, d As Integer) Declare Constructor(value As rational) Declare Constructor() Declare Destructor() Declare Function toString() As String End Type
Constructor rational(n As Integer, d As Integer) This.numerator=n This.denominator=d Print "created: ";Str(n);" ";Str(d);" ";@This End Constructor
Constructor rational() This.numerator=0 This.denominator=1 Print "*created: ";Str(0);" ";Str(1);" ";@This End Constructor
Constructor rational(value As rational) This.numerator=0 This.denominator=1 Print "**created: ";Str(0);" ";Str(1);" ";@This End Constructor
Destructor rational() Print "destroyed ";@This End Destructor
Function rational.toString() As String Return Str(This.numerator)+"/"+Str(This.denominator) End Function
'' Умножает два рациональных типа Function rational_multiply( r1 As rational, r2 As rational ) As rational Print "enter mult" Dim r As rational '' умножить делители ... r.numerator = r1.numerator * r2.numerator r.denominator = r1.denominator * r2.denominator '' ... и вернуть результат Print "exit mult" Return r
End Function
Sub main() Dim r1 As rational=Rational(1,2) Dim r2 As rational=Rational(1,3) Dim r3 As rational'=rational_multiply(r1,r2) r3=rational_multiply(r1,r2) Print r3.toString() Sleep End Sub
main() Sleep
|
|
| |
haav | Дата: Среда, 01.04.2020, 19:17 | Сообщение # 11 |
Генералиссимус
Группа: Администраторы
Сообщений: 1374
Статус: Offline
| Цитата catstail ( ) Если некий объект создается в стеке, а потом ссылка на него возвращается из функции, то память, в которой расположен объект, может быть затерта при вызове другой функции. Ну я же выше писал как происходит возврат объектов из функции с картинками Ладно повторю, наверное плохо объяснил. Вот код:
Код type OBJ i as Long End Type function GETOBJ() as OBJ dim pObj as OBJ = type(100) return pObj End Function dim p as OBJ = GETOBJ() ? p.i sleep
В данном случае объект p не является объектом pObj , но является его копией.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
haav | Дата: Среда, 01.04.2020, 19:37 | Сообщение # 12 |
Генералиссимус
Группа: Администраторы
Сообщений: 1374
Статус: Offline
| Цитата bxusinboy ( ) Вот это скрытый конструктор: Если конструктор скрыт , тогда как-то сомнительно выглядит выскакивающий деструктор. По крайней мере для меня нелогично такое поведение.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
bxusinboy | Дата: Среда, 01.04.2020, 19:43 | Сообщение # 13 |
Рядовой
Группа: Пользователи
Сообщений: 16
Статус: Offline
| Цитата haav ( ) Если конструктор скрыт , тогда как-то сомнительно выглядит выскакивающий деструктор. По крайней мере для меня нелогично такое поведение. Тут такой конструктор не указан:
Код Declare Constructor(value As rational)
Но деструктор один для этих всех конструкторов:
По этому, где написан Print там выскакивается, где не написан там не выскакивает, я думаю.
|
|
| |
catstail | Дата: Среда, 01.04.2020, 19:47 | Сообщение # 14 |
Рядовой
Группа: Пользователи
Сообщений: 7
Статус: Offline
| Как будто-бы так и есть - добавил конструктор копирования:
Код Type rational '' Простой тип rational numerator As Integer denominator As Integer Declare Constructor(n As Integer, d As Integer) Declare Constructor(f As rational) ' копирующий конструктор Declare Constructor() Declare Destructor() Declare Function toString() As String End Type
Constructor rational(f As rational) this.numerator=f.numerator this.denominator=f.denominator Print "*created: ";Str(f.numerator);" ";Str(f.denominator);" ";@This End Constructor
Constructor rational(n As Integer, d As Integer) this.numerator=n this.denominator=d Print "created: ";Str(n);" ";Str(d);" ";@This End Constructor
Constructor rational() this.numerator=0 this.denominator=1 Print "*created: ";Str(0);" ";Str(1);" ";@This End Constructor
Destructor rational() Print "destroyed ";@This End Destructor
Function rational.toString() As String Return Str(this.numerator)+"/"+Str(this.denominator) End Function
'' Умножает два рациональных типа Function rational_multiply( r1 As rational, r2 As rational ) As rational Print "enter mult" Dim r As rational '' умножить делители ... r.numerator = r1.numerator * r2.numerator r.denominator = r1.denominator * r2.denominator '' ... и вернуть результат Print "exit mult" Return r
End Function
Sub main() Dim r1 As rational=Rational(1,2) Dim r2 As rational=Rational(1,3) Dim r3 As rational'=rational_multiply(r1,r2) r3=rational_multiply(r1,r2) Print r3.toString() Sleep End Sub
main() Sleep
Теперь конструкторы и деструкторы "на балансе":
created: 1 2 1375876 created: 1 3 1375868 *created: 0 1 1375860 enter mult *created: 0 1 1375824 exit mult *created: 1 6 1375852 destroyed 1375824 destroyed 1375852 1/6 destroyed 1375860 destroyed 1375868 destroyed 1375876
|
|
| |
bxusinboy | Дата: Среда, 01.04.2020, 19:49 | Сообщение # 15 |
Рядовой
Группа: Пользователи
Сообщений: 16
Статус: Offline
| Если вы посмотрели мой пример, там выскакивает 5 created = 5 destroyed.
|
|
| |
|