Reputation: 83254
I have the following function and structures in C++ code that are designed for interop:
extern "C" __declspec(dllexport) typedef struct
{
int num_vertices;
int *vertices;
} Vertex_List;
extern "C" __declspec(dllexport) typedef struct
{
int num_cycles;
Vertex_List *cycles;
} Cycle_List;
extern "C" __declspec(dllexport) typedef struct
{
int v1;
int v2;
} Edge;
extern "C" __declspec(dllexport) typedef struct
{
int num_edges;
Edge *edgeList;
} Edge_List;
extern "C" __declspec(dllexport) Cycle_List Traversal(Edge_List edgeList);
And This is my corresponding .Net structure code:
[StructLayout(LayoutKind.Sequential)]
internal struct EdgeSpecial
{
public int v1;
public int v2;
}
[StructLayout(LayoutKind.Sequential)]
internal struct Edge_List
{
public int num_edges;
public IntPtr edgeList;
}
[StructLayout(LayoutKind.Sequential)]
internal struct Vertex_List
{
public int num_vertices;
public IntPtr vertices;
}
[StructLayout(LayoutKind.Sequential)]
internal struct Cycle_List
{
public int num_cycles;
public IntPtr cycles;
}
[DllImport("BoostAPI.dll")]
public static extern Cycle_List Traversal([In] Edge_List edgeList);
This is how I do my call in .Net function:
//converts from my edge structure to the interop structure
Edge_List edgeList = EdgeConvertor(edges);
//interop call
Cycle_List cycleInterop = GraphBoostInterop.Traversal(edgeList);
// converts from interop cycle structure to my .NET structure
var cycleList = CycleListConvertor(cycleInterop);
The issue is, after the cycleInterop
is converted to my data structure cycleList
, is there any need to free edgeList
and cycleInterop
? Should I create FreeCycle
or such code inside C++ and then pass the structure into it for freeing the memory purpose? If yes, how?
Edit: This is how the Cycle_List is populated in C++; basically I just copy the information from a similar data structure ( using std::vector
to it).
i=0;
Cycle_List cList;
cList.num_cycles=cycleList.CycleList.size();
cList.cycles=(Vertex_List*)malloc(cList.num_cycles*sizeof(Vertex_List));
for(std::vector<Cycle>::const_iterator it = cycleList.CycleList.begin(); it != cycleList.CycleList.end(); ++it)
{
Cycle cycle = *it;
Vertex_List vList;
vList.num_vertices = cycle.VertexList.size();
vList.vertices= (int*) malloc ( vList.num_vertices*sizeof(int));
j=0;
for(std::vector<int>::const_iterator intList=cycle.VertexList.begin(); intList!=cycle.VertexList.end(); ++intList)
{
vList.vertices[j++] = *intList;
}
cList.cycles[i++]=vList;
}
Upvotes: 2
Views: 213
Reputation: 54734
Because you're populating the Cycle_List
structure inside your own C++ code, you should write a second C++ function that frees a Cycle_List
structure.
Since you're using malloc
to initialize the Cycle_List::cycles
and Vertex_List::vertices
members, you should use free
to clean them up.
As @Aliostad says, "responsibility of the releasing is by whoever has allocated the memory".
Upvotes: 1
Reputation: 81660
Responsibility of the releasing is by whoever has allocated the memory. As simple as it seem, this is the golden rule.
According to this rule, when an unmanaged DLL returns me a pointer to an unmanaged structure it means that it has allocated the memory. So releasing the memory would require calling the unmanaged DLL to release it when you are done - which seems to be at the time you finish converting the unmanaged pointer to managed structure.
I am not familiar with your unmanaged library but I have used OpenCV and it has cvRelease(**ptr)
which releases the memory and resets the pointer back to zero.
Upvotes: 1