-2

I'm writing a c# / cpp mixed program and need to call some cpp functions inside c#. For most of the functions, I can just use PInvoke approach to call extern cpp funcs.

// cpp part
void compute(DataWrapper* dataHolderFromCSharp){
    computeNatively(dataHolderFromCSharp);
}
// c# part
void useData(cppData){
  var cppData = cppWrapper.compute(preRes);
  doSthWith(cppData);
}

However, some cpp functions will need a pre-computed class from other cpp functions. Instead of re-compute such a "pre-computed" class every time, I'd like to store it somewhere so that it lives through the lifecycle of the main c# program.

// cpp part
void preCompute(DataWrapper* dataHolderFromCSharp, customClass & preComputeRes){
    precomputeNatively(dataHolderFromCSharp, preComputeRes);
}

void compute(DataWrapper* dataHolderFromCSharp, customClass* preComputeRes, DataWrapper* workData){
    preCompute(dataHolderFromCSharp, preComputeRes);
    doComputation(preComputeRes, workData);
}

void computeOverride(DataWrapper* dataHolderFromCSharp, DataWrapper* workData){
    customClass* preComputeRes, 
    preCompute(dataHolderFromCSharp, preComputeRes);
    doComputation(preComputeRes, workData);
}
// c# part
void useData(cppData){
  cppWrapper.computeOverride(DataWrapper, otherDataWrapper);
}

But this will cause the preCompute() to run every time.

Instead, I want to do something like the following:

// c# part
static IntPtr preRes;

void useData(cppData){
  if (signalChanged)
    preRes = cppWrapper.preCompute(); // how to store the precomputed data?
  
  cppWrapper.compute(DataWrapper, preRes, otherDataWrapper);
}

The question is what is the proper way to store (on the c# side) such an access point of class (computed the on the cpp side) so that I can re-use it without re-compute it every time?

Creating a static class in the cpp side in memory and send a pointer to the c# side so that I can always access it?

X.Arthur
  • 277
  • 2
  • 13
  • 1
    `return &preComputeRes;` is extremely wrong. You are returning a pointer to an object that gets destroyed right after. That is a dangling pointer, you cannot use that – UnholySheep May 02 '22 at 14:15
  • 2
    `return &preComputeRes;` -- TL;DR. This is a non-starter. This won't work for C++, let alone C#. – PaulMcKenzie May 02 '22 at 14:18
  • Unlike C#, that `preComputeRes` is a local object that automatically gets destroyed once it leaves scope. Deterministic destruction doesn't exist in C# AFAIK, it does in C++. Using `&preComputeRes` doesn't create a reference to it so as to make it survive outside the function. – PaulMcKenzie May 02 '22 at 14:25
  • 1
    The issue has to do with scope and variable lifetimes in C++. Very little, if anything, has to do with C#. You basically must ensure that `preComputeRes` has a lifetime that outlives any usage of it (global, static local, allocated witn `new`, etc.) – PaulMcKenzie May 02 '22 at 14:46
  • That's why I want to store it as a static member or element in the c# side. But don't know how to pass it as a class... – X.Arthur May 02 '22 at 14:48
  • @X.Arthur -- Forget about C# for a moment. Can you get your idea to work for C++? If you do, then that same idea will work for C#. By posting bad C++ code, you've missed the point being made, IMO. We've already mentioned your idea (bad code) will not work for C++, even though it may compile. – PaulMcKenzie May 02 '22 at 14:51
  • @PaulMcKenzie Modified. I know how to do it without the pre-computed part. The question now should be more clear. – X.Arthur May 02 '22 at 15:02
  • You wrap your CPP functionality with COM and access the class via COM interop. – R.J. Dunnill May 02 '22 at 17:20

2 Answers2

-1

You don't need to store a pointer to a native cpp object in the .net part of your application. The best way here is to create an api in the native library to initialize a global instance of the object and of course an api to clean it (you can use a singleton to store the pointer). This way the object will live inside your native enviroment. Then you can remove any reference to this global object from the parameters of all the other apis because they will use the global instance inside them. This way you can use the classical PInvoke interface

Marco Beninca
  • 605
  • 4
  • 15
  • There's a lot of caveats to this advice, starting with the obvious fact that a singleton can only have a single instance. If OP needs to have more than one instance then this answer does not help – UnholySheep May 02 '22 at 15:02
-1

Update:

I resolve this by creating a static class in cpp side, and return a pointer to the c# side as a handle to access it.

// cpp 

static customClass preComputeRes;

customClass * preCompute(DataWrapper* dataHolderFromCSharp){
    precomputeNatively(dataHolderFromCSharp, preComputeRes);
    return & preComputeRes;
}

void compute(customClass * preComputeRes, DataWrapper* workData){
    doComputation(preComputeRes, workData);
}

// c#
void useData(){
  if (signalChanged || signalNew)
    preRes = cppWrapper.preCompute(); // store the handle
  
  cppWrapper.compute(DataWrapper, preRes, otherDataWrapper);
}

The only issue is I'm not sure if the memory of that static class will be release when the c# app is closed. Potential memory leak?

X.Arthur
  • 277
  • 2
  • 13