東方算程譚

Oriental Code Talk ── επιστημηが与太をこく、弾幕とは無縁のシロモノ。

目次

Blog 利用状況

ニュース

著作とお薦めの品々は

著作とお薦めの品々は
東方熱帯林へ。

あわせて読みたい

わんくま

  1. 東京勉強会#2
    C++/CLI カクテル・レシピ
  2. 東京勉強会#3
    template vs. generics
  3. 大阪勉強会#6
    C++むかしばなし
  4. 東京勉強会#7
    C++むかしばなし
  5. 東京勉強会#8
    STL/CLRによるGeneric Programming
  6. TechEd 2007 @YOKOHAMA
    C++・C++/CLI・C# 適材適所
  7. 東京勉強会#14
    Making of BOF
  8. 東京勉強会#15
    状態遷移
  9. 名古屋勉強会#2
    WinUnit - お気楽お手軽UnitTest

CodeZine

  1. Cで実現する「ぷちオブジェクト指向」
  2. CUnitによるテスト駆動開発
  3. SQLiteで組み込みDB体験(2007年版)
  4. C++/CLIによるCライブラリの.NET化
  5. C# 1.1からC# 3.0まで~言語仕様の進化
  6. BoostでC++0xのライブラリ「TR1」を先取りしよう (1)
  7. BoostでC++0xのライブラリ「TR1」を先取りしよう (2)
  8. BoostでC++0xのライブラリ「TR1」を先取りしよう (3)
  9. BoostでC++0xのライブラリ「TR1」を先取りしよう (4)
  10. BoostでC++0xのライブラリ「TR1」を先取りしよう (5)
  11. C/C++に対応した、もうひとつのUnitTestFramework ─ WinUnit
  12. SQLiteで"おこづかいちょう"
  13. STL/CLRツアーガイド
  14. マージ・ソート : 巨大データのソート法
  15. ヒープソートのアルゴリズム
  16. C++0xの新機能「ラムダ式」を次期Visual Studioでいち早く試す
  17. .NETでマンデルブロ集合を描く
  18. .NETでマンデルブロ集合を描く(後日談)
  19. C++/CLI : とある文字列の相互変換(コンバージョン)
  20. インテルTBBによる選択ソートの高速化
  21. インテルTBB3.0 によるパイプライン処理
  22. Visual C++ 2010に追加されたSTLアルゴリズム
  23. Visual C++ 2010に追加されたSTLコンテナ「forward_list」
  24. shared_ptrによるObserverパターンの実装
  25. .NETでマンデルブロ集合を描く(番外編) ── OpenCLで超並列コンピューティング
  26. StateパターンでCSVを読む
  27. 状態遷移表からStateパターンを自動生成する
  28. 「ソートも、サーチも、あるんだよ」~標準C++ライブラリにみるアルゴリズムの面白さ
  29. インテルTBBの同期メカニズム
  30. なぜsetを使っちゃいけないの?
  31. WPFアプリケーションで腕試し ~C++でもWPFアプリを
  32. C++11 : スレッド・ライブラリひとめぐり
  33. Google製のC++ Unit Test Framework「Google Test」を使ってみる
  34. メールでデータベースを更新するココロミ
  35. Visitorパターンで遊んでみたよ
  36. Collection 2題:「WPFにバインドできる辞書」と「重複を許す検索set」
  37. Visual C++ 2012:stateless-lambdaとSQLiteのぷち拡張
  38. 「Visual C++ Compiler November 2012 CTP」で追加された6つの新機能

@IT

  1. Vista時代のVisual C++の流儀(前編)Vista到来。既存C/C++資産の.NET化を始めよう!
  2. Vista時代のVisual C++の流儀(中編)MFCから.NETへの実践的移行計画
  3. Vista時代のVisual C++の流儀(後編) STL/CLRによるDocument/Viewアーキテクチャ
  4. C++開発者のための単体テスト入門 第1回 C++開発者の皆さん。テスト、ちゃんとしていますか?
  5. C++開発者のための単体テスト入門 第2回 C++アプリケーションの効率的なテスト手法(CppUnit編)
  6. C++開発者のための単体テスト入門 第3回 C++アプリケーションの効率的なテスト手法(NUnit編)

AWARDS


Microsoft MVP
for Visual Developer - Visual C++


Wankuma MVP
for いぢわる C++


Nyantora MVP
for こくまろ中国茶

Xbox

Links

記事カテゴリ

書庫

日記カテゴリ

.Netはすごく難しいのかもしれない

.Netは難しいのかもしれない のつづき。

NyaRuRuさんにコメントいただきました:

「自身の破壊的変更を行うインターフェイス」を
値型に実装させるのは避けるべし,という話ですが...

そーなのかー。 ではさらにぢっけん:

interface Idata { int data { get; } } // 破壊しないぞ!

struct Val : Idata {
  private int d;
  public int data
    { get { return d; } }
  public void setVal(int n) { d = n; } // setは別枠
}

class Program {
  public static void Main() {
    Idata x, y;
    x = new Val();
    y = x;
    ((Val)x).setVal(123); // Val化して値変更
    System.Console.WriteLine(
       "Idata of Val: x={0}, y={1}", x.data, y.data);
  }
}

結果はx,yともに0となります。
((Val)x).setVal(123); が機能してない(よに見えます)。

これはどう解釈すんだ?
interfaceを値型(struct)にcast-downするとコピーが返されるてことスカ?

さらにsiokoshouさんからは:

インターフェース型は参照型なので、
インターフェース型に値型を入れたらbox化されます。

ですって。
だとしたら((Val)x).setVal(123);によって両方とも
123になんないのはナゼでスカ?

# んー、ダークサイドが見え隠れ。好きですけどねこーゆーの ^^;

投稿日時 : 2007年10月31日 13:54

コメントを追加

# re: .Netはすごく難しいのかもしれない 2007/10/31 14:54 シャノン

> interfaceを値型(struct)にcast-downするとコピーが返されるてことスカ?

ソですね。
un-boxing するとコピーが作られるはずです。

# re: .Netはすごく難しいのかもしれない 2007/10/31 15:05 επιστημη

なるほどー。
ならinterfaceが参照型でも矛盾は生じんわけだ。
「自己破壊メソッドを実装するな」とも繋がるなりね。

# re: .Netはすごく難しいのかもしれない 2007/10/31 15:19 NyaRuRu

ちなみに IL レベルでは unboxing と unboxing 後のコピーは別物です.
んで,C# の文法はこの 2 つをセットにしてしまっていて,unboxing だけを行うことができません.
boxing と unboxing は本来非対称なのですが,C# のこの挙動のせいで対象的な動作と誤解されることが多いようです.(と先ほど紹介した Jeff 本にも書いてあります)

# re: .Netはすごく難しいのかもしれない 2007/10/31 15:46 επιστημη

> boxing と unboxing は本来非対称なのですが

boxing: コピーをこさえて箱に入れ、フタをする。
unboxing: 箱のフタを開けて中身を晒す
cast-back@C#: 箱のフタを開けて中身を晒し、
        コピーをこさえてフタをする。

って感じなのかにゃ。

# re: .Netはすごく難しいのかもしれない 2007/10/31 17:02 siokoshou

呼ばれたから書こうとしたらすでに回答が出てるのでIL話でも(^^;
Box化/Unbox化はILを見ると(人によっては)わかりやすいかもです。

ローカル変数
.locals init ([0] class Idata x,
[1] class Idata y,
[2] valuetype Val CS$0$0000)
~省略~
IL_0012: ldloc.0 // xを取り出して
IL_0013: unbox.any Val // Unbox化して
IL_0018: stloc.2 // ローカル変数にコピー
IL_0019: ldloca.s CS$0$0000
IL_001b: ldc.i4.s 123
IL_001d: call instance void Val::setVal(int32) // コピーに対してsetVal(123)実行
IL_0022: nop
IL_0023: ldstr "Idata of Val: x={0}, y={1}"
~略~

Unbox化してローカル変数にコピーしたものに対して操作して、その後そのコピーしたものにさわるコードがありません。

値型にインターフェースはこのコピー動作のおかげでパフォーマンス的にも無駄なので、極力避けてます。

# re: .Netはすごく難しいのかもしれない 2007/10/31 17:45 NyaRuRu

ちょっと補足.
値型 T について,
 unbox.any T

 unbox T
 ldobj T
と等価です.
この場合は管理下ポインタの取得とポイント先のコピーがセットで行われます.
こちらの場合は C# の (T) と綺麗に対応します.
(unbox.any は Generics 対応のために .NET 2.0 で追加された命令です)

# re: .Netはすごく難しいのかもしれない 2007/10/31 18:28 siokoshou

ああ、そうだ…肝心なところでorz
ILはスタックマシンなのでスタックにコピーしてからストアですね。
復習してきます…。

# re: .Netはすごく難しいのかもしれない 2007/11/01 1:35 RUN

ん~、話が難しすぎて入っていけないorz

単純に
((Val)x)の時点で、新しくメモリ領域を確保して(便宜上sxと名づける)そのsxに対してsetValを実行している訳だから、sx.dの値が123となる。
もちろんsxはxではないのでx.dは0のまま。
その後、sxに対する参照を保持している変数が無い為、sxはそのまま行方不明となる。
って考え方だと間違ってますかね?
構造体へのキャストの動きを想像すると、キャストした時に新しいインスタンスを生成しているんじゃないかという気がするのですが、勘違いですかね?

# 俺流インターフェイスの解釈2 2007/11/08 22:43 むりせず♪なまけず? ~ぷろくらすてぃねいたーの言い訳雑記~

俺流インターフェイスの解釈2

# 俺流インターフェイスの解釈2 2007/11/08 22:46 むりせず♪なまけず? ~ぷろくらすてぃねいたーの言い訳雑記~

俺流インターフェイスの解釈2

タイトル
名前
URL
コメント