FreeBasic
Главная
Вход
Регистрация
Пятница, 19.04.2024, 17:53Приветствую Вас Гость | RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Форум » Freebasic » Вопросы по языку FreeBasic » Управление памятью (Возможность возвращения "локальных" объектов)
Управление памятью
catstailДата: Понедельник, 30.03.2020, 17:05 | Сообщение # 1
Рядовой
Группа: Пользователи
Сообщений: 7
Репутация: 0
Статус: 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
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата catstail ()
В VB это возможно. Можно и динамический массив так вернуть. А как обстоит дело во FB? Сохранится ли a после возврата?

Я бы не стал на такое полагаться в FB.


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
catstailДата: Понедельник, 30.03.2020, 21:58 | Сообщение # 3
Рядовой
Группа: Пользователи
Сообщений: 7
Репутация: 0
Статус: 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
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: 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
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: 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" и ими можно без опасения пользоваться. Однако следует не забывать , что стек конечен , поэтому увлекаться большим кол-вом таких объектов , а особенно объектов с большим размером не стоит. Именно поэтому я придерживаюсь практики указателей.
Прикрепления: 9316097.png (34.2 Kb) · 8339789.png (10.2 Kb)


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
catstailДата: Среда, 01.04.2020, 14:35 | Сообщение # 6
Рядовой
Группа: Пользователи
Сообщений: 7
Репутация: 0
Статус: 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
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: 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


И тебе понятнее и людям легче вникнуть в суть вопроса.  Мне кстати интересно как стек может мешать принципам правильности данного примера? То что он работает криво , вызывая лишний раз деструктор , это я понимаю (наверное это баг, кстати размещу на оф. форуме данный код , может пофиксят или меня поправят smile ) , но твое утверждение как бы говорит о том , что подобная реализация в принципе не может размещать объекты в стеке. Я правильно понял ? Если да, то почему ты так считаешь?


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
haavДата: Среда, 01.04.2020, 18:46 | Сообщение # 8
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: 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
Репутация: 0
Статус: Offline
Ок. Я беспокоюсь вот о чем. Если некий объект создается в стеке, а потом ссылка на него возвращается из функции, то память, в которой расположен объект, может быть затерта при вызове другой функции. В C/C++ так нельзя. А в VB можно. Но в VB менеджер памяти (как в Java), это очень расслабляет. 

Мое отношение к ООП аналогично. Но, вообще-то, это вещь удобная. Поэтому пренебрегать не стоит. 

По поводу бага... Есть подозрение, что имеет место теневой вызов конструктора копирования. В C++ я с этим сталкивался. Позже приведу код на C++.
Решил заняться FB, т.к. появилось желание делать приложения, независимые от Microsoft. FB, как мне кажется, для этого идеально подходит. Но требует привычки. Что я и вырабатываю.
 
bxusinboyДата: Среда, 01.04.2020, 19:05 | Сообщение # 10
Рядовой
Группа: Пользователи
Сообщений: 16
Репутация: 2
Статус: 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
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата catstail ()
Если некий объект создается в стеке, а потом ссылка на него возвращается из функции, то память, в которой расположен объект, может быть затерта при вызове другой функции.

Ну я же выше писал как происходит возврат объектов из функции с картинками smile  Ладно повторю, наверное плохо объяснил. Вот код:

Код
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
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата bxusinboy ()
Вот это скрытый конструктор:

Если конструктор скрыт , тогда как-то сомнительно выглядит выскакивающий деструктор. По крайней мере для меня нелогично такое поведение.


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
bxusinboyДата: Среда, 01.04.2020, 19:43 | Сообщение # 13
Рядовой
Группа: Пользователи
Сообщений: 16
Репутация: 2
Статус: Offline
Цитата haav ()
Если конструктор скрыт , тогда как-то сомнительно выглядит выскакивающий деструктор. По крайней мере для меня нелогично такое поведение.

Тут такой конструктор не указан:
Код
Declare Constructor(value As rational)

Но деструктор один для этих всех конструкторов:
Код
Declare Destructor()

По этому, где написан Print там выскакивается, где не написан там не выскакивает, я думаю.
 
catstailДата: Среда, 01.04.2020, 19:47 | Сообщение # 14
Рядовой
Группа: Пользователи
Сообщений: 7
Репутация: 0
Статус: 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
Репутация: 2
Статус: Offline
Если вы посмотрели мой пример, там выскакивает 5 created = 5 destroyed.
 
Форум » Freebasic » Вопросы по языку FreeBasic » Управление памятью (Возможность возвращения "локальных" объектов)
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск: