none
Native types and Generics RRS feed

  • Question

  • I want to create a native array and access it managed code. I don't want to re write code to different types, (int, long, float, double) therefore tried using generics. 

    	typedef int IND;
    
    	generic <typename T>
    	public ref class ntvarray
    	{
    	private:
    		void *pnt;
    		IND sz;
    
    	public:
    		ntvarray(IND length)
    		{
    			sz = sizeof(T);
    			pnt = ::operator new(length*sz);
    		}
    
    		~ntvarray()
    		{
    			::operator delete(pnt);
    		}
    
    		void* pointer()
    		{
    			return pnt;
    		}
    
    		T getitem (IND index)
    		{
    			//c3229
    			return ((T*)pnt)[index];
    		}
    
    		void setitem (IND index, T value)
    		{
    			//c3229
    			((T*)pnt)[index] = value;
    		}
    	};
    

     

    I am getting the error and I know the reason for this error,

    error C3229: 'T *' : indirections on a generic type parameter are not allowed

     

    However is there a way to do this using generics?

     

    Any other way to do this, may be something else other than using generics?


    Actually I want to reuse this class with several types inside the managed code.

     Generics doesn't support  explicit specialization.Managed code links this code is in c#, which cannot use c++ template classes.

    Is there a solution?

    • Edited by Anniffer Friday, July 1, 2011 7:05 PM More information
    Friday, July 1, 2011 3:29 PM

Answers

  • JIT translates managed code to machine-specific native machine code at first launch, you get a delayed cold start but you are executing native image thereafter.

    There is a penalty of a few CPU cycles to do managed-native transition (COM calls included), almost nothing on modern CPUs if the amount of calls is small. There is a much higher cost if you need to move a lot of data across (e.g. a lot of ntvarray_double::getitem calls) since memory access goes to the sometimes-congested main bus of your motherboard. If you do not want to only expose the controlling interface and must expose a lot of data, try batch the operations to avoid the managed-native transition cost. But i would prefer the data stay where they are as much as possible.



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    • Marked as answer by Anniffer Wednesday, July 6, 2011 2:31 PM
    Tuesday, July 5, 2011 9:48 PM

All replies

  • void* in .Net is IntPtr. You can store a memory address in IntPtr and later use it ,like copying a memory block of size sizeof(float) starting at the address to a block on the stack or on the managed heap. 

     



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP
    Friday, July 1, 2011 8:24 PM
  • void* in .Net is IntPtr. You can store a memory address in IntPtr and later use it ,like copying a memory block of size sizeof(float) starting at the address to a block on the stack or on the managed heap. 

     



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP
    Friday, July 1, 2011 8:24 PM
  • I don't understand how the IntPtr can be useful here. Can you please give some code snippets?

    Do you mean I should copy the data across (back and forth between unmanaged and managed)? Copying the data across is never going to be a solution, - arrays are going to be in hundreds of megabytes.

    Do you have any point to relate generics with IntPtr?


    Saturday, July 2, 2011 5:20 PM
  • IntPtr is a managed type capable of storing an address on the native heap or on the stack. You can use the Marshal class to copy data from a memory address to the stack or managed heap.

    Your generic class has a method copying one array element from native memory to the managed stack. If this is never to be a solution then you need to think something else (e.g. write pure native code and only expose controlling interface via COM, like what XNA is doing).

     



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP
    Saturday, July 2, 2011 6:46 PM
  • Oh! It's interesting.. Thanks, you pointed out it is actually marshalling the data across.

    Performance of this piece of code is key in my project, used in a real time processing.

    Leaving the generic class aside, I created a similar class, hard coded to double instead of using generics. I performed a simple performance test, using System.Diagnostics  tools and compared the performance with a double[]  managed array.

      C++/CLI

    	public ref class ntvarray_double
    	{
    	private:
    		double* arr; IND len;
    
    	public:
    		ntvarray_double(IND length)
    		{ 
    			len = length; 
    			arr = new double[len];
    		}
    
    		~ntvarray_double()
    		{ delete arr; }
    
    		double* getarray(void)
    		{ return arr; }
    
    		double getitem(IND index)
    		{ return arr[index]; }
    
    		void setitem(IND index, double value)
    		{ arr[index] = value; }
    
    		property IND Length
    		{ IND get() { return len; } }
    	};
    

     

     

    C#

        private void but_use_Click(object sender, EventArgs e)
        {
          int i, j, c, r;
    
          long[] times;
    
          Stopwatch sw;
          sw = new Stopwatch();
          times = new long[10];
    
          r = 1000000;
          c = 10000;
    
          ntvarray_double narr;
          double[] marr;
    
          narr = new ntvarray_double(c);      
          marr = new double[c];
    
          sw.Reset(); sw.Start();
          for (j = 0; j < r; j++) 
          for (i = 0; i < c; i++) narr.setitem(i, i);
          sw.Stop();
          times[0] = sw.ElapsedMilliseconds;
    
          sw.Reset(); sw.Start();
          for (j = 0; j < r; j++) 
          for (i = 0; i < c; i++) marr[i] = i;
          sw.Stop();
          times[1] = sw.ElapsedMilliseconds;
    
          for (i=0; i<times.Length; i++)
            lst_disp.Items.Add(times[i]);
        }
    


    I expected Managed array to perform better. But results are surprisingly almost equal!

    Accessing times for (Native Array,  Managed Array):
    (15640,16660) , (17944,16592) , (18092,16525) , (15527,16575)

    What does this mean? Why?

    1. marshalling puts no extra work, or insignificant time?

    2. .Net Runtime is clever enough to do something  (eg: function in-lining) with the functions inside the native array C++/CLI wrapper class?

    3. Some other factors skewing  this test?

     

    Although COM interface seems to be an ultimate solution, can you comment about the relative performance of a COM interface? (I haven't tried to implement it, yet)

    Saturday, July 2, 2011 8:21 PM
  • JIT translates managed code to machine-specific native machine code at first launch, you get a delayed cold start but you are executing native image thereafter.

    There is a penalty of a few CPU cycles to do managed-native transition (COM calls included), almost nothing on modern CPUs if the amount of calls is small. There is a much higher cost if you need to move a lot of data across (e.g. a lot of ntvarray_double::getitem calls) since memory access goes to the sometimes-congested main bus of your motherboard. If you do not want to only expose the controlling interface and must expose a lot of data, try batch the operations to avoid the managed-native transition cost. But i would prefer the data stay where they are as much as possible.



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    • Marked as answer by Anniffer Wednesday, July 6, 2011 2:31 PM
    Tuesday, July 5, 2011 9:48 PM