RAII

C++ ではローカル変数はスタック上に確保され, スコープを抜けるとデストラクタが 呼ばれて破棄された.

これを利用してリソースの確保と解放を行うのが RAII という技法である.

D では RAII と同様の機能を scope 属性と scope クラスで実現できる.

scope 属性

まずは, C++ での RAII の例

raii.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

class Foo{
public: // public を使わないとエラーになる
  Foo(){
    std::cout << "Foo" << std::endl;
  }
  ~Foo(){
    std::cout << "~Foo" << std::endl;
  }
};

int main(){
  std::cout << "{" << std::endl;
  {
    Foo a;
  }
  std::cout << "}" << std::endl;
  return 0;
}
  

raii.cpp の実行結果は:

[cactus:~/code_d/d_tuts]% ./raii
{
Foo
~Foo
}

D 言語では, インスタンスの破棄はガベージコレクタ (GC) の仕事なのでスコープを抜けてもデストラクタが呼ばれたり破棄されたりしない.

RAII を実現するためには scope キーワードを使う.

raii.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import std.stdio;

class Foo{
  private int id;
  this(int i){
    id = i;
    writeln("this: ", id);
  }
  ~this(){
    writeln("~this: ", id);
  }
}

void main(){
  // 明示的に delete
  writeln("{");
  {
    Foo a = new Foo(1);
    delete a;
  }
  writeln("}");

  // GC に任せる
  writeln("{");
  {
    Foo a = new Foo(2);
  }
  writeln("}");

  // RAII
  writeln("{");
  {
    scope Foo a = new Foo(3);
  }
  writeln("}");
}

raii.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./raii
{
this: 1
~this: 1
}
{
this: 2
}
{
this: 3
~this: 3
}
~this: 2

“~this:2” と “~this:3” が呼ばれているタイミングの違いに注目

scope クラス

scope 属性を付加したローカル変数は変数宣言時に後から追加するものだった.

これに対して, クラスの設計として RAII を使用しており常に scope 属性を付加すべき ならば, scope クラスとして定義する方法が適している.

scope.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
scope class Foo{
}

class Bar : Foo{
}

void main(){
  // Foo a = new Foo;
  scope Foo b = new Foo;
  scope Bar c = new Bar;
}

scope クラスは定義時に scope 属性を付加したクラス.

scope クラスは scope 属性付きのローカル変数しか作成できない.

scope 属性は継承される.

Table Of Contents

Previous topic

GC (ガベージコレクタ)

Next topic

テンプレートメタプログラミング