unsafe static void SquarePtrParam (int* p)
{
*p *= *p;
}
VS
static void SquarePtrParam (ref int p)
{
p *= p;
}
答案 0 :(得分:11)
安全代码可以在任何可以运行C#代码(Silverlight,共享托管ASP.NET,XNA,SQL Server等)的情况下运行,而不安全的代码需要提升信任。这意味着您可以在更多地方运行代码,并且限制更少。
此外,它是安全的,这意味着您不必担心做错事情并使您的流程崩溃。
答案 1 :(得分:9)
您的示例不是很好,JIT编译器已经生成了类似的代码。在引擎盖下引用也是指针。这需要快速,托管代码永远不会具有竞争力。
垃圾收集堆与指针非常不兼容,您必须固定对象才能创建指向它们的指针。如果没有固定,垃圾收集器可能会移动对象,并且您的代码会随机失败,从而破坏堆的完整性。固定操作和效率损失都是非零成本,在取消固定后,当固定对象时发生垃圾收集。
指针在访问非托管内存时非常有效。规范示例是需要访问位图像素的图像处理。这是一种快速访问固定数组的方法,删除了所有安全联锁,当你不迭代它们时,数组索引检查不是免费的。
答案 2 :(得分:7)
使用不安全代码的原因只有一个:原始性能。
使用不安全的代码,您可以像指针一样使用C ++,而无需经过运行时检查。没有检查意味着你自己,但开销较少。
我只是在加速图像/位图操作时才看到它。但是你也可以用它来进行内联字符串操作(是的,使字符串变得可变!!!不管怎么说,除非你想构建StringBuilder)。其他用法包括矩阵计算或其他重数学。并且可能与操作系统接口,以及一些黑客攻击。
答案 3 :(得分:2)
一本完美的例子在J.Richter“CLR via C#”,3 edition,Ch。 16: 以下C#代码演示了三种用于访问二维数组的技术(安全,锯齿和不安全):
using System;
using System.Diagnostics;
public static class Program {
private const Int32 c_numElements = 10000;
public static void Main() {
const Int32 testCount = 10;
Stopwatch sw;
// Declare a two-dimensional array
Int32[,] a2Dim = new Int32[c_numElements, c_numElements];
// Declare a two-dimensional array as a jagged array (a vector of vectors)
Int32[][] aJagged = new Int32[c_numElements][];
for (Int32 x = 0; x < c_numElements; x++)
aJagged[x] = new Int32[c_numElements];
// 1: Access all elements of the array using the usual, safe technique
sw = Stopwatch.StartNew();
for (Int32 test = 0; test < testCount; test++)
Safe2DimArrayAccess(a2Dim);
Console.WriteLine("{0}: Safe2DimArrayAccess", sw.Elapsed);
// 2: Access all elements of the array using the jagged array technique
sw = Stopwatch.StartNew();
for (Int32 test = 0; test < testCount; test++)
SafeJaggedArrayAccess(aJagged);
Console.WriteLine("{0}: SafeJaggedArrayAccess", sw.Elapsed);
// 3: Access all elements of the array using the unsafe technique
sw = Stopwatch.StartNew();
for (Int32 test = 0; test < testCount; test++)
Unsafe2DimArrayAccess(a2Dim);
Console.WriteLine("{0}: Unsafe2DimArrayAccess", sw.Elapsed);
Console.ReadLine();
}
private static Int32 Safe2DimArrayAccess(Int32[,] a) {
Int32 sum = 0;
for (Int32 x = 0; x < c_numElements; x++) {
for (Int32 y = 0; y < c_numElements; y++) {
sum += a[x, y];
}
}
return sum;
}
private static Int32 SafeJaggedArrayAccess(Int32[][] a) {
Int32 sum = 0;
for (Int32 x = 0; x < c_numElements; x++) {
for (Int32 y = 0; y < c_numElements; y++) {
sum += a[x][y];
}
}
return sum;
}
private static unsafe Int32 Unsafe2DimArrayAccess(Int32[,] a) {
Int32 sum = 0;
fixed (Int32* pi = a) {
for (Int32 x = 0; x < c_numElements; x++) {
Int32 baseOfDim = x * c_numElements;
for (Int32 y = 0; y < c_numElements; y++) {
sum += pi[baseOfDim + y];
}
}
}
return sum;
}
}
Unsafe2DimArrayAccess方法标有unsafe修饰符,这是必需的 使用C#的固定语句。要编译此代码,您必须在调用C#编译器时指定/ unsafe开关,或者在Microsoft Visual Studio的“项目属性”窗格的“生成”选项卡上选中“允许不安全代码”复选框。 当我在我的机器上运行该程序时,我得到以下输出:
00:00:02.0017692: Safe2DimArrayAccess
00:00:01.5197844: SafeJaggedArrayAccess
00:00:01.7343436: Unsafe2DimArrayAccess
如您所见,安全的二维数组访问技术是最慢的。安全的锯齿状阵列访问技术比安全的二维阵列访问技术花费的时间少一些。但是,您应该注意,创建锯齿状数组比创建多维数组更耗时,因为创建锯齿状数组需要在堆上为每个维分配一个对象,从而导致垃圾收集器定期启动。因此需要权衡:如果您需要创建大量“多维数组”并且您打算不经常访问这些元素,则创建多维数组会更快。如果您只需要创建一次“多维数组”,并且经常访问其元素,则锯齿状数组将为您提供更好的性能。当然,在大多数应用程序中,后一种情况更为常见。
答案 4 :(得分:1)
我不认为在您给出的示例中使用不安全的代码是有利的。当我需要与非托管代码进行交互时,我才真正使用了不安全的代码,例如在调用非com dll接口时。