From: Eric W. <ewm...@gm...> - 2013-01-29 09:59:29
|
>> > Ah right I see, yes, %delobject isn't right for what you want. What you > want are constructor and destructor type functionality for C structs. > This is covered in the Basics chapter: > file:///home/william/swig/github/swig/Doc/Manual/SWIG.html#SWIG_adding_member_functions > > So for example you use %extend like this to add in a 'destructor' (I > havn't put in a constructor wrapper for you, assuming you want your > users to just call ALmixer_LoadAll, but you can design this however you > want): > > %module example > > %newobject ALmixer_LoadAll; > %extend ALmixer_Data { > ~ALmixer_Data() { > ALmixer_FreeData($self); > } > }; > > %inline %{ > struct ALmixer_Data { > int x; > }; > typedef struct ALmixer_Data ALmixer_Data; > ALmixer_Data* ALmixer_LoadAll(const char* file_name) { > printf("ALmixer_LoadAll\n"); > return (ALmixer_Data *)malloc(sizeof(ALmixer_Data)); > } > void ALmixer_FreeData(ALmixer_Data* almixer_data) { > printf("ALmixer_FreeData\n"); > free(almixer_data); > } > %} > > The following lua script: > > sound = example.ALmixer_LoadAll("test.wav") > sound = nil > collectgarbage() > print("Finished") > > when run then shows it working as you want: > > ALmixer_LoadAll > ALmixer_FreeData > Finished > > If you omit %newobject, then the ALmixer_FreeData is not called. > YES! This is exactly what I needed to know! It seems to be working for me now for my real test case in Lua. So follow up question. I'm concerned about the (re)definition of the struct ALmixer_Data in the swig file. In my actual code, ALmixer_Data is an opaque struct from the public API. The API only uses it as a pointer, so the real definition is hidden inside the implementation file and is intentionally not exposed. In the real public header, there is only a forward declaration of: typedef struct ALmixer_Data ALmixer_Data; I'm worried that by (re)defining the ALmixer struct with as: %inline %{ struct ALmixer_Data { int x }; %} this may cause me clashing problems with the real implementation. But if I try to skip this inline definition, I get the warning: ../ALmixer.i:88: Warning 303: %extend defined for an undeclared class ALmixer_Data. And the generated code doesn't produce the correct/needed auto cleanup code in this case. So if I put the struct (re)definition back in, then things work, but I noticed some areas that concern me a little. For example, this function gets created which actually does a malloc on the sizeof(ALmixer_Data). ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static int _wrap_new_Data(lua_State* L) { int SWIG_arg = 0; struct ALmixer_Data *result = 0 ; SWIG_check_num_args("ALmixer_Data::ALmixer_Data",0,0) result = (struct ALmixer_Data *)calloc(1, sizeof(struct ALmixer_Data)); SWIG_NewPointerObj(L,result,SWIGTYPE_p_ALmixer_Data,1); SWIG_arg++; return SWIG_arg; if(0) SWIG_fail; fail: lua_error(L); return SWIG_arg; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// I'm not exactly sure what that is doing, but it does worry me a little bit. Can you reassure this redefinition is safe and the correct thing to do, or tell me if there is a better way to do it? For reference, this is the excerpt in my .i file: ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// %newobject ALmixer_LoadAll; %newobject ALmixer_LoadStream; %delobject ALmixer_FreeData; typedef struct ALmixer_Data ALmixer_Data; %extend ALmixer_Data { ~ALmixer_Data() { ALmixer_FreeData($self); } }; %inline %{ struct ALmixer_Data { int x }; %} ALmixer_Data* ALmixer_LoadAll(const char* file_name, ALuint access_data); ALmixer_Data* ALmixer_LoadStream(const char* file_name, ALuint buffer_size, ALuint max_queue_buffers, ALuint num_startup_buffers, ALuint suggested_number_of_buffers_to_queue_per_update_pass, ALuint access_data); void ALmixer_FreeData(ALmixer_Data* almixer_data); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// >> Does any of this make sense/ring a bell? Is there an actual solution >> for this that already exists? > Maybe the docs are not clear enough, but this is the way it is meant to > work. Patches to the docs to improvement are welcome. > > William So I think are several different things that would make this clearer. - The section is titled "Adding member functions to C structures". I was looking for the keywords "memory management". I don't think of memory management as adding functions. Perhaps a section explicitly called "Automatic memory management for C structs with garbage collected languages" would help search visibility. - "Destructors" make me think of C++ and not C and it wasn't obvious to me that this applied to C also. - The example you gave me in this email was very explicit and exactly to the heart of what I was trying to do. This is a really important concept for C bindings so I think this example should go into the docs so people see they should be doing this. I'll see if I can take a stab at improving the documentation once I get a better understanding of that redefinition of the struct question. Thanks, Eric -- Beginning iPhone Games Development http://playcontrol.net/iphonegamebook/ |