Graviton
Graviton

Reputation: 83254

Should the Interop Structure Memory be Freed After Calling?

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

Answers (2)

Tim Robinson
Tim Robinson

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

Aliostad
Aliostad

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

Related Questions