C#의 들쭉날쭉 한 배열에서 이중 포인터로 변환
-
23-08-2019 - |
문제
간단한 질문 여기 : 들쭉날쭉 한 배열에서 이중 포인터로 변환 할 수있는 방법이 있습니까?
EG 변환 a double[][]
에게 double**
불행히도 (평범한 C에서 가능한 것처럼) 불행히도 이것은 캐스팅하는 것만으로도 할 수 없습니다. 사용 a fixed
진술도 문제를 해결하지 못하는 것 같습니다. c#에서 이것을 달성 할 수있는 방법이 있습니까? 그럼에도 불구하고 솔루션이 전혀 분명하지 않을 수도 있지만, 그럼에도 불구하고 솔루션이 직접적으로 희망합니다.
해결책
Double [] []는 Double*이 아닌 Double []의 배열이므로 Double **을 얻으려면 먼저 Double* []가 필요합니다.
double[][] array = //whatever
//initialize as necessary
fixed (double* junk = &array[0][0]){
double*[] arrayofptr = new double*[array.Length];
for (int i = 0; i < array.Length; i++)
fixed (double* ptr = &array[i][0])
{
arrayofptr[i] = ptr;
}
fixed (double** ptrptr = &arrayofptr[0])
{
//whatever
}
}
나는 이것이 무엇인지 궁금해 할 수 없으며 더블 포인터를 요구하는 것보다 더 나은 솔루션이 있는지 궁금합니다.
다른 팁
약간의 안전.
첫 번째 솔루션에 대한 의견에 언급했듯이 중첩 어레이를 이동할 수 있으므로 고정해야합니다.
unsafe
{
double[][] array = new double[3][];
array[0] = new double[] { 1.25, 2.28, 3, 4 };
array[1] = new double[] { 5, 6.24, 7.42, 8 };
array[2] = new double[] { 9, 10.15, 11, 12.14 };
GCHandle[] pinnedArray = new GCHandle[array.Length];
double*[] ptrArray = new double*[array.Length];
for (int i = 0; i < array.Length; i++)
{
pinnedArray[i] = GCHandle.Alloc(array[i], GCHandleType.Pinned);
}
for (int i = 0; i < array.Length; ++i)
{
// as you can see, this pointer will point to the first element of each array
ptrArray[i] = (double*)pinnedArray[i].AddrOfPinnedObject();
}
// here is your double**
fixed(double** doublePtr = &ptrArray[0])
{
Console.WriteLine(**doublePtr);
}
// unpin all the pinned objects,
// otherwise they will live in memory till assembly unloading
// even if they will went out of scope
for (int i = 0; i < pinnedArray.Length; ++i)
pinnedArray[i].Free();
}
문제에 대한 간단한 설명 :
힙에 일부 물체를 할당하면 쓰레기 수집의 다른 위치로 이동할 수 있습니다. 따라서 다음 상황을 상상해보십시오. 일부 물체와 내부 배열을 할당했으며 모두 힙에 0 세대에 배치됩니다.
이제 일부 물체는 범위에서 나와 쓰레기가되었으며 일부 물체는 방금 할당되었습니다. 쓰레기 수집가는 오래된 물체를 힙에서 옮기고 다른 물체를 시작 또는 차세대에 더 가깝게 옮기고 힙을 압축합니다. 결과는 다음과 같습니다.
따라서 우리의 목표는 힙의 일부 물체를 "고정"하는 것입니다. 이 목표를 달성하기 위해 무엇을해야합니까? 우리는 가지고 있습니다 결정된 진술 및 gchandle.ALLOGATE 방법.
먼저, 무엇을 GCHandle.Allocate
하다? 매개 변수로 메소드로 전달 된 객체를 참조하는 내부 시스템 테이블에서 새 항목을 만듭니다. 따라서 쓰레기 수집가가 힙을 검사 할 때, 그는 내부 테이블에 항목을 확인하고, 그가 하나를 찾을 때, 그는 물체를 살아있는 것으로 표시하고 그것을 힙에서 옮기지 않을 것입니다. 그런 다음 그는이 객체가 고정 된 방법을보고 압축 단계에서 메모리에서 객체를 움직이지 않을 것입니다. fixed
문은 스코프를 떠날 때 "UNPINS"객체를 자동으로 제외하고는 거의 동일합니다.
요약 : 고정 된 각 객체 fixed
그가 스코프를 떠나면 자동으로 "innipned"되지 않습니다. 우리의 경우, 다음 번 루프 반복에있을 것입니다.
객체가 이동하거나 쓰레기를 수집하지 않는지 확인하는 방법 : 제로 세대에 대한 모든 힙 예산을 소비하고 GC를 강제로 쌓아 힙을 압축하십시오. 다시 말해, 힙에 많은 객체를 만듭니다. 그리고 당신이 당신의 물건을 고정하거나“고정”후에 그것을하십시오.
for(int i = 0; i < 1000000; ++i)
{
MemoryStream stream = new MemoryStream(10);
//make sure that JIT will not optimize anything, make some work
stream.Write(new Byte[]{1,2,3}, 1, 2);
}
GC.Collect();
작은 통지 : 큰 물체와 작은 물체에는 두 가지 유형의 힙이 있습니다. 객체가 크면 코드를 확인하기 위해 큰 개체를 만들어야합니다. 그렇지 않으면 작은 물체가 GC가 쓰레기 수집 및 압축을 시작하도록 강요하지 않습니다.
마지막으로, 여기에는 몇 가지 샘플 코드가 있습니다.이 샘플 코드는 다음과 같습니다. 관심이없는 사람을 위해 미부린/고정되지 않은 포인터로 기본 배열에 액세스 할 수있는 위험을 보여줍니다.
namespace DangerousNamespace
{
// WARNING!
// This code includes possible memory access errors with unfixed/unpinned pointers!
public class DangerousClass
{
public static void Main()
{
unsafe
{
double[][] array = new double[3][];
array[0] = new double[] { 1.25, 2.28, 3, 4 };
array[1] = new double[] { 5, 6.24, 7.42, 8 };
array[2] = new double[] { 9, 10.15, 11, 12.14 };
fixed (double* junk = &array[0][0])
{
double*[] arrayofptr = new double*[array.Length];
for (int i = 0; i < array.Length; i++)
fixed (double* ptr = &array[i][0])
{
arrayofptr[i] = ptr;
}
for (int i = 0; i < 10000000; ++i)
{
Object z = new Object();
}
GC.Collect();
fixed (double** ptrptr = &arrayofptr[0])
{
for (int i = 0; i < 1000000; ++i)
{
using (MemoryStream z = new MemoryStream(200))
{
z.Write(new byte[] { 1, 2, 3 }, 1, 2);
}
}
GC.Collect();
// should print 1.25
Console.WriteLine(*(double*)(*(double**)ptrptr));
}
}
}
}
}
}
나는 당분간 Zachrrs 솔루션과 함께 갔다. 여기에는 확장 방법이 있습니다.
public static double** ToPointer(this double[][] array)
{
fixed (double* arrayPtr = array[0])
{
double*[] ptrArray = new double*[array.Length];
for (int i = 0; i < array.Length; i++)
{
fixed (double* ptr = array[i])
ptrArray[i] = ptr;
}
fixed (double** ptr = ptrArray)
return ptr;
}
}