Jump to content
  • Advertisement
Sign in to follow this  
droz

Holding refererences to objects

This topic is 3151 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm working on implementing a template array system like std::vector. I've ran into a problem with the data I'm storing being released, I'm not sure how to hold a reference to it. If I create a variable in the scripting language and then add it to the array it will work without problems, but if I just try to push a value it gets released before I want it to. Example:
vector<int> Array;
int tmp = 4;
Array.pushBack(3);
Array.pushBack(tmp);

Out << Array.At(0); // This will not work because the value was destroyed.
Out << Array.At(1); // This will work

Here is the code for the array class (some of the code was borrowed from the stringarray addon):
/**
 ** eScript
 **   Copyright 2008, 2009 (c) Jeremy Harmon
 **
 **
 ** eScript is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 ** the Free Software Foundation; either version 2 of the License, or
 ** (at your option) any later version.
 **
 ** eScript is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 **
 ** You should have received a copy of the GNU General Public License
 ** along with eScript; if not, write to the Free Software
 ** Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 ** 02110-1301  USA
 **
 ** Jeremy Harmon
 **  <jeremyh_net@users.sourceforge.net>
 **/

#include <Core/Stdlib/Array.h>
#include <angelscript.h>
#include <assert.h>

namespace Stdlib {

Array *ArrayDefaultFactory(asIObjectType *objType) {
    return new Array(objType);
}

static bool ScriptArrayTemplateCallback(asIObjectType *ot)

{

	// Make sure the subtype can be instanciated with a default factory/constructor, 

	// otherwise we won't be able to instanciate the elements

	int typeId = ot->GetSubTypeId();

	if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) )

	{

		asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId);

		asDWORD flags = subtype->GetFlags();

		if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) )

		{

			// Verify that there is a default constructor

			for( int n = 0; n < subtype->GetBehaviourCount(); n++ )

			{

				asEBehaviours beh;

				int funcId = subtype->GetBehaviourByIndex(n, &beh);

				if( beh != asBEHAVE_CONSTRUCT ) continue;



				asIScriptFunction *func = ot->GetEngine()->GetFunctionDescriptorById(funcId);

				if( func->GetParamCount() == 0 )

				{

					// Found the default constructor

					return true;

				}

			}



			// There is no default constructor

			return false;

		}

		else if( (flags & asOBJ_REF) )

		{

			// Verify that there is a default factory

			for( int n = 0; n < subtype->GetFactoryCount(); n++ )

			{

				int funcId = subtype->GetFactoryIdByIndex(n);

				asIScriptFunction *func = ot->GetEngine()->GetFunctionDescriptorById(funcId);

				if( func->GetParamCount() == 0 )

				{

					// Found the default factory

					return true;

				}

			}	



			// No default factory

			return false;

		}

	}



	// The type is ok

	return true;

}

Array::Array(asIObjectType *objType) {
    m_gcFlag    = false;
    m_refCount  = 1;
    m_objType   = objType;

    // Add another reference to the object
    m_objType->AddRef();

    if(m_objType->GetFlags() & asOBJ_GC)
        m_objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, m_objType->GetTypeId());
}

Array::~Array() {
    if(m_objType)
        m_objType->Release();
}

void Array::Register(asIScriptEngine *pEngine) {
    int Ret;

    Ret = pEngine->RegisterObjectType("newArray<class T>", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert(Ret >= 0);
    Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in)", 
                                            asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert(Ret >= 0);


    Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_FACTORY, "newArray<T>@ f(int&in)", asFUNCTION(ArrayDefaultFactory), asCALL_CDECL); assert(Ret >= 0);
	Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(Array,addRef), asCALL_THISCALL); assert(Ret >= 0);

	Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(Array,Release), asCALL_THISCALL); assert(Ret >= 0);
    Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(Array, getRefCount), asCALL_THISCALL); assert(Ret >= 0);

	Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(Array, setFlag), asCALL_THISCALL); assert(Ret >= 0);

	Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(Array, getFlag), asCALL_THISCALL); assert(Ret >= 0);

	Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(Array, enumRefs), asCALL_THISCALL); assert(Ret >= 0);

	Ret = pEngine->RegisterObjectBehaviour("newArray<T>", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(Array, releaseAllHandles), asCALL_THISCALL); assert(Ret >= 0);



	Ret = pEngine->RegisterObjectMethod("newArray<T>", "void pushBack(T &in)", asMETHOD(Array, pushBack), asCALL_THISCALL); assert(Ret >= 0);

	Ret = pEngine->RegisterObjectMethod("newArray<T>", "T &At(uint &in)", asMETHOD(Array, At), asCALL_THISCALL); assert(Ret >= 0);
}

void Array::pushBack(void *pData) {
    m_Array.push_back(pData);
}

void *Array::At(uint &Pos) {
    return m_Array.at(Pos);
}

void Array::enumRefs(asIScriptEngine *pEngine) {
    int typeId = m_objType->GetSubTypeId();
    if(typeId & asTYPEID_MASK_OBJECT) {
        std::vector<void*>::iterator Iter;
        for(Iter = m_Array.begin(); Iter != m_Array.end(); Iter++) {
            if((*Iter))
                pEngine->GCEnumCallback(*Iter);
        }
    }
}

void Array::releaseAllHandles(asIScriptEngine *pEngine) {
    int subTypeId = m_objType->GetSubTypeId();
    asIObjectType *subType = pEngine->GetObjectTypeById(subTypeId);
    if(subType && subType->GetFlags() & asOBJ_GC) {
        std::vector<void*>::iterator Iter;
        for(Iter = m_Array.begin(); Iter != m_Array.end(); Iter++) {
            if((*Iter)) {
                pEngine->ReleaseScriptObject(*Iter, subTypeId);
                *Iter = NULL;
            }
        }
    }
}

void Array::addRef() {
    m_gcFlag = false;
    m_refCount++;
}

void Array::Release() {
    m_gcFlag = false;
    if(--m_refCount == 0)
        delete this;
}

int Array::getRefCount() {
    return m_refCount;
}

void Array::setFlag() {
    m_gcFlag = true;
}

bool Array::getFlag() {
    return m_gcFlag;
}

} // End Namespace Stdlib

Thanks, Jeremy

Share this post


Link to post
Share on other sites
Advertisement
You cannot hold the references to value types (including primitives). You need to copy the value instead of storing a pointer to it.

If you store the pointer it will become invalid as soon as the variable goes out of scope, which for temporary values is immediately.

Regards,
Andreas

Share this post


Link to post
Share on other sites
Thanks for adding template support, this will allow me to have a much better array system for my project. It took a while to figure out how to create and populate a array inside of my program. When getting the object type to pass to the array I was trying to use GetTypeByDecl("string"), took me a while to realize I need to use "array<string>".

Thanks for your hard work on AngelScript!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!