いまさら配列のシャローコピー!? な感じがあるけれど整理。
きっかけはClone()
を用いてコピーを取っているのを見たこと。
結果から言えば無知にもとづく認識だったのだけれど、Clone()
は使わない方がよさそうと思っていた。
Clone と銘打ちながらジェネリックでないためキャストが必要になるし、ICloneable
インターフェースは実装しないことが推奨されているし……。
ICloneable インターフェイス (System) | Microsoft Learn
ところがふとArray.Clone
を見てみると、Intrinsic
属性が付いていた。
Source Browser (Array.Clone)
参考:JIT Intrinsics | ++C++; // 未確認飛行 C ブログ(Intrinsic)
使わない方がよいと思っていたAPIにパフォーマンスのための属性がついているとは――、ということで確認してみることにした。
2次元配列の複製において、Clone()
、Array.Copy
Buffer.BlockCopy
、ループを BenchmarkDotNet にて計測。
private readonly int[,] source = new int[256, 256]; [GlobalSetup] public void Setup() { int xl = source.GetLength(0); int yl = source.GetLength(1); int i = 0; for (int x = 0; x < xl; x++) { for (int y = 0; y < yl; y++) { source[x, y] = i++; } } } [Benchmark] public int[,] ByClone() => (int[,])source.Clone(); [Benchmark] public int[,] ByArrayCopy() { int[,] dest = new int[source.GetLength(0),source.GetLength(1)]; Array.Copy(source, dest, source.Length); return dest; } [Benchmark] public int[,] ByBlockCopy() { int[,] dest = new int[source.GetLength(0), source.GetLength(1)]; Buffer.BlockCopy(source, 0, dest, 0, sizeof(int) * source.Length); return dest; } [Benchmark] public int[,] ByLoop() { int xl = source.GetLength(0); int yl = source.GetLength(1); int[,] dest = new int[xl, yl]; for (int x = 0; x < xl; x++) { for (int y = 0; y < yl; y++) { dest[x, y] = source[x, y]; } } return dest; }
Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated | ------------ |---------:|----------:|---------:|--------:|--------:|--------:|----------:| ByClone | 135.4 μs | 56.59 μs | 3.10 μs | 83.2520 | 83.2520 | 83.2520 | 256.07 KB | ByArrayCopy | 134.8 μs | 81.71 μs | 4.48 μs | 83.2520 | 83.2520 | 83.2520 | 256.07 KB | ByBlockCopy | 135.7 μs | 20.82 μs | 1.14 μs | 83.2520 | 83.2520 | 83.2520 | 256.07 KB | ByLoop | 246.7 μs | 225.55 μs | 12.36 μs | 83.0078 | 83.0078 | 83.0078 | 256.07 KB |
今回については前3者は実質同速とみなせそうに見える。
これならば、単純なシャローコピーなら簡潔なClone()
でいい、と言える気がする。
もちろんケースによっては積極的に選ばない(例えばバッファをArrayPool
から用意、となれば使えない)ものの、少なくとも、使わないほうがよさそうという曖昧な忌避感は誤認だった。