HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Returning handles

08-22-2009, 06:38 PM#1
Maxus
I'm not sure about one thing. I have a function that returns unit:
Collapse JASS:
function CinemAltarFind takes player whichPlayer returns unit
    local group tempGroup = GetUnitsOfPlayerMatching(whichPlayer, Condition(function CinemAltarFilter))
    local unit altar = GroupPickRandomUnit(tempGroup)
    call DestroyGroup(tempGroup)
    set tempGroup = null
    return altar
endfunction
The function makes a group of all altars owned by a player and then returns random altar.
I intent to use it somewhere like this:
Collapse JASS:
set someVariable = CinemAltarFind(Player(0))

The problem is that I create a local variable unit, then set it to be random... and return it. I know that handle types are called-by-reference and I know that I should destroy handle types and it is even better to nullify the local variables (that's what I'm doing with tempGroup).

As far as I know this doesn't have to be done with parameters that a function takes (don't I have to destroy them?), but what about return types? It would probably be stupid to nullify altar variable, but still I'm not sure if this will cause a memory leak. Can anyone please explain how exactly this works? What happens to the local reference altar and what happens to the unit itself?
08-22-2009, 06:46 PM#2
Vexorian
The local reference would leak. The returned unit (handle) itself has to be cleaned later, by another function.

To prevent the reference leak you need something like this:

Collapse JASS:
globals
    private unit returnunit
endglobals

function CinemAltarFind takes player whichPlayer returns unit
    local group tempGroup = GetUnitsOfPlayerMatching(whichPlayer, Condition(function CinemAltarFilter))
    local unit altar = GroupPickRandomUnit(tempGroup)
    call DestroyGroup(tempGroup)
    set tempGroup = null
    set returnunit = altar
    set altar = null
    return returnunit
endfunction

You probably need to do better than GetUnitsOfPlayerMatching, that BJ has a memory leak of its own.
08-22-2009, 07:07 PM#3
Maxus
thanx, what about this:
Collapse JASS:
function CinemAltarFind takes player whichPlayer returns nothing
    local group tempGroup = CreateGroup()
    call GroupEnumUnitsOfPlayer(tempGroup, whichPlayer, Condition(function CinemAltarFilter))
    set udg_altar = GroupPickRandomUnit(tempGroup)
    call DestroyGroup(tempGroup)
    set tempGroup = null
endfunction

Will this leak? Now udg_altar is just a global unit, but I'm not sure about the boolexpr used as filter...
08-22-2009, 08:51 PM#4
0zyx0
Condition() returns a boolexpr, which you would have to destroy every time it has been used. Or you could use the same boolexpr every time, if you create it at map initialization.
08-22-2009, 08:59 PM#5
azlier
Condition and Filter return the same boolexpr for the same code every time. No leaks there. If you destroy it, future attempts at using it won't work[citation needed]. Never again.

Try testing this:
Collapse JASS:
scope Test initializer Init

private function Actions takes nothing returns boolean
    if Condition(function Actions) == Condition(function Actions) then
        call BJDebugMsg("Condition(function Actions) == Condition(function Actions)")
    else
        call BJDebugMsg("Condition(function Actions) != Condition(function Actions)")
    endif
    
    if Filter(function Actions) == Filter(function Actions) then
        call BJDebugMsg("Filter(function Actions) == Filter(function Actions)")
    else
        call BJDebugMsg("Filter(function Actions) != Filter(function Actions)")
    endif
    
    if Filter(function Actions) == Condition(function Actions) then
        call BJDebugMsg("Filter(function Actions) == Condition(function Actions)")
    else
        call BJDebugMsg("Filter(function Actions) != Condition(function Actions)")
    endif
    return false
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterPlayerEvent(t, Player(0), EVENT_PLAYER_END_CINEMATIC)
    call TriggerAddCondition(t, Condition(function Actions))
endfunction

endscope
08-22-2009, 10:08 PM#6
Vexorian
Quote:
No leaks there. If you destroy it, future attempts at using it won't work. Never again.
I don't think destroying boolexprs created by Condition does anything at all.

If you use And() it will "leak" and DestroyBoolexpr will do something, but if you used Condition() it seems to do nothing.
08-23-2009, 08:55 AM#7
Maxus
Quote:
You probably need to do better than GetUnitsOfPlayerMatching, that BJ has a memory leak of its own.
That's why I changed into using GroupEnumUnitsOfPlayer, if you look here:
Expand GetUnitsOfPlayerMatching:

As you see they did destroy the boolexpr in that BJ (I didn't when I switched to GroupEnumUnitsOfPlayer). And it worked as many times as wanted while I was using GetUnitsOfPlayerMatching, there just was that unit group reference leak.

As boolexpr filter I use Condition(function CinemAltarFilter) where function CinemAltarFilter is always the same defined at map initialization.
The code used to create boolexpr is always the same, but whereas code is native and cannot leak, boolexpr is handle. So I don't know whether it creates new boolexpr from the same code every time it is used (it would probably leak).
Quote:
If you use And() it will "leak" and DestroyBoolexpr will do something, but if you used Condition() it seems to do nothing.
And And() takes two boolexpr and returns also boolexpr, maybe that's why it is more likely to leak