...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

続・shared_ptr

19:00 余計な処理を入れていたみたいなので削除しました.

今のD言語では opAssign(T)() が定義できないらしい.
どうもD言語の shared_ptr に boost::shared_ptr のような多態性を持たせるのは無理な気がするがどうなんだろう.


とりあえず上記のことはD言語の仕様として諦めた.
カウンタをstaticメンバにしたらオブジェクトとカウンタの対応関係を作らないといけなくなったので連想配列を使用する shared_ptr を作ったw
あとスレッドアンセーフ.
よくわからないけどこんなもんなのかなあ.

ソースは続きに.

import std.stdio;

struct shared_ptr(T) if(is(T == class))
{
private:
	static int n[T];
	T p;
	alias p this;
	
public:
	static shared_ptr!T opCall(U)(U p)
	{
		shared_ptr!T ret;
		ret.p = p;
		ret.n[p]++;
		debug writefln("opCall(T) ", ret.n[p]);
		return ret;
	}
	
	this(this)
	{
		n[p]++;
		debug writeln("postblit ", n[p]);
	}
	
	ref shared_ptr!T opAssign(shared_ptr!T t)
	{
		p = t.p;
		n[p]++;
		debug writeln("opAssign ", n[p]);
		return this;
	}
	
	~this()
	{
		n[p]--;
		debug writeln("dtor ", n[p]);
		assert(n[p] >= 0);
		if(n[p] == 0)
		{
			delete p;
			debug writeln("deleted");
		}
	}
}

class A
{
	void f() {writeln("I am A.");}
	this() { writeln("A.this"); }
	~this() { writeln("A.~this"); }
}
class B : A
{
	void f() {writeln("I am B.");}
	this() { writeln("B.this"); }
	~this() { writeln("B.~this"); }
}

scope class C // 実験のためCはscope
{
	shared_ptr!A sa;
	this(shared_ptr!A sa)
	{
		this.sa = sa;
		assert(shared_ptr!A.n[sa.p] == 2);
	}
}

shared_ptr!A g;

void set(A a)
{
	assert(shared_ptr!A.n[a] == 0);
	auto x = shared_ptr!A(a);
	assert(shared_ptr!A.n[a] == 1);
	g = x;
	assert(shared_ptr!A.n[a] == 2);
}

void main()
{
	writeln("\n* 1. opCall(shared_ptr!T) and postblit *");
	{
		auto a = new A;
		auto sa = shared_ptr!A(a); // opCall
		assert(shared_ptr!A.n[a] == 1);
		auto sb = sa; // postblit
		assert(shared_ptr!A.n[a] == 2);
		sa.f();
		sb.f();
	}
	writeln("\n* 2. opAssign(shared_ptr!T) *");
	{
		auto a = new A;
		shared_ptr!A sa;
		sa = shared_ptr!A(a); // opAssign
		assert(shared_ptr!A.n[a] == 1);
		sa.f();
	}
	writeln("\n* 3. polymorphic with opCall *");
	{
		auto b = new B;
		shared_ptr!A sa = shared_ptr!B(b); // polymorphic with opCall
		assert(shared_ptr!A.n[b] == 1);
		assert(shared_ptr!B.n[b] == 1);
		sa.f();
	}
	writeln("\n* 4. polymorphic with opAssign *");
	{
		// opAssign(T t)とopAssign(U)(U u)がconflictすると言われて
		// 定義することができないので無理?
		
//		auto b = new B;
//		shared_ptr!A sa;
//		sa = shared_ptr!B(b); // polymorphic with opAssign
//		assert(shared_ptr!A.n[b] == 1);
//		assert(shared_ptr!B.n[b] == 1);
//		sa.f();
	}
	writeln("\n* 5. polymorphic with function call *");
	{
		// 同様にむりぽ
		
//		void polySet(shared_ptr!A sa)
//		{
//			assert(shared_ptr!A.n[sa.p] == 2);
//		}
//		auto sb = shared_ptr!B(new B);
//		polySet(sb);
//		assert(shared_ptr!A.n[sb.p] == 1);
//		assert(shared_ptr!B.n[sb.p] == 1);
	}
	writeln("\n* 6. class member *");
	{
		auto a = new A;
		scope c = new C(shared_ptr!A(a));
		assert(shared_ptr!A.n[a] == 1);
		scope d = c;
		assert(shared_ptr!A.n[a] == 1); // dは参照なので1でいいはず
	}
	writeln("\n* 7. global *");
	{
		auto a = new A;
		set(a);
		assert(shared_ptr!A.n[a] == 1);
	}
	writeln("\n<-- the end of main");
}

static ~this()
{
	assert(g.n[g.p] == 1); // まだ残っている
	writeln("\n<-- the end of static ~this");
}

追加

実行結果を載せ忘れてた.

* 1. opCall(shared_ptr!T) and postblit *
A.this
opCall(T)
postblit 2
dtor 1
postblit 2
I am A.
I am A.
dtor 1
dtor 0
A.~this
deleted

* 2. opAssign(shared_ptr!T) *
A.this
opCall(T)
postblit 2
dtor 1
opAssign 2
dtor 1
I am A.
dtor 0
A.~this
deleted

* 3. polymorphic with opCall *
A.this
B.this
opCall(T)
postblit 2
dtor 1
opCall(T)
postblit 2
dtor 1
I am B.
dtor 0
B.~this
A.~this
deleted

* 4. polymorphic with opAssign *

* 5. polymorphic with function call *

* 6. class member *
A.this
opCall(T)
postblit 2
dtor 1
postblit 2
opAssign 3
dtor 2
dtor 1
dtor 0
A.~this
deleted

* 7. global *
A.this
opCall(T)
postblit 2
dtor 1
postblit 2
opAssign 3
dtor 2
dtor 1

<-- the end of main

<-- the end of static ~this
A.~this