2013年4月14日日曜日

Apr.14

この日は自動投票の調子が良かった。
4勝の堅め打ちで前日の負債も帳消しに出来た。

皐月賞は前日の予想どおりに◎ラブリーデイの単複
ペースが流れて道中で脚を使わされてしまった。距離が長かったのかもしれないし、スローの瞬発力勝負のほうがあっているのかもしれない。
ロゴタイプは強かった。
WIN5の軸に出来るくらいのパフォーマンスだった。


自動投票と手動投票を併用している。
どちらも同じロジックを基本にして馬券を購入。
手動はアナログ予想のフィルタをかけて重ね買いを推奨している。
自動投票が購入しないレースは推奨馬が複数共存していることがあるので手動で単勝以外の式別を併用するチャンスでもある。

日曜の阪神7Rは、その典型で5頭の推奨馬。
自動投票は複数推奨馬に人気馬が含まれており期待値から投票を回避していた。
アナログ予想で推奨馬プルーフポジティブの好走の可能性は低いと判断して消してオッズから次のように順番をつけた。

◎ヒルノマドリード(7番人気)
◎ドリームチャージ(11番人気)
△オーシャンドライブ(1番人気)
△キクタロウ(2番人気)

馬券は馬連、馬単◎-◎△のフォーメーションで各5点
結果は◎ヒルノマドリード1着、△オーシャンドライブ2着で馬連4460円、馬単9980円

こういうレースを週にひとつ獲れるようになると潤滑油となってより回収率が安定してくる。

2013年4月13日土曜日

Apr.13

朝、揺れた。
それ以上にXperia Zに地震速報が通知されなかったことに驚く。
設定が必要だったのか。

出掛ける予定だったので競馬は見れず。
自動投票を仕掛けておくもExceptionが発生。Xperiaを使って出先からPCを操作して修正してみたがExceptionを取り除くことはできなかった。
それなのに家に帰ってから見直すと簡単に直った。
冷静さはやはり必要。

自動投票が失敗していたことが功を奏して、被害が広がらずに済んだ。
つまり、結果が散々だったということ。
先週も絶不調で4月は自動抽出馬は1頭しか勝ち上がっていない。
ここは踏ん張りどころ。

日曜のWIN5を検討してみたが、確勝級のレースを見つけることができず断念。
やはりいまの予算で5レースを全て的中させるのは不可能。
4レースに絞ってから買うというスタンスをとりあえずはとりつづけるつもり。

皐月賞◎にはラブリーデイを指名。
自動抽出該当馬であり、血統、騎手、厩舎、馬主、生産者だけならG1級。

2013年1月4日金曜日

typedefのおさらい

C#のプロパティような振る舞いを実装するで関数ポインタをtypedefで定義したのですが少し手間取りました。

///
/// 符号あり16ビット長をINT16と定義する
///
typedef signed short INT16

「signed short」を「INT16」に定義するとずっと思い込んでいたのが間違いでした。正確には「typedef <型宣言>」のようで関数ポインタを定義するには次のようにすれば良いようです。

///
/// プロパティクラスの宣言の一部
///
template<typename H, typename T>
class Property
{
 typedef T (H::*GET)(void) const;
 typedef void (H::*SET)(const T&);
 
 H* _host;
 GET _get;
 SET _set;
};

このように定義するとGETとSETという名前で関数ポインタを扱うことができるようになります。

C#のプロパティような振る舞いを実装する

C#のgetter/setterのようなことがC++でもやりたくなりました。
メンバ変数とメンバ関数の経由部分をテンプレートクラスで実装します。

プロパティ機能を提供するテンプレートクラス
///
/// Property.h
///
#ifndef _INC_PROPERTY_H_
#define _INC_PROPERTY_H_

namespace Test {

template<typename H, typename T>
class Property
{
 typedef T (H::*GET)(void) const;
 typedef void (H::*SET)(const T&);

 H* _host;
 GET _get;
 SET _set;

 ///
 /// _hostに代入する術がないのでガード
 ///
 Property(const Property<H, T>& other);

public:
 Property(H* host, GET get, SET set);
 ~Property();
 operator T() const;
 Property<H, T>& operator=(const T& val);
 Property<H, T>& operator=(const Property<H, T>& other);
};

template<typename H, typename T>
Property<H, T>::Property(H* host, GET get, SET set)
 : _host(host), _get(get), _set(set)
{
}

template<typename H, typename T>
Property<H, T>::~Property()
{
}

template<typename H, typename T>
Property<H, T>::operator T() const
{
 return (this->_host->*_get)();
}

template<typename H, typename T>
Property<H, T>& Property<H, T>::operator=(const T& val)
{
 (this->_host->*_set)(val);
 return *this;
}

template<typename H, typename T>
Property<H, T>& Property<H, T>::operator=(const Property<H, T>& other)
{
 (this->_host->*_set)((other._host->*_get)());
 return *this;
}

}
#endif

getterとsetterは静的メンバ関数でないので関数ポインタでアクセスする場合、オブジェクトを指定する必要があります。どのオブジェクトのアクセッサを使うか判別するため、事前に_hostにオブジェクトを登録しておきます。コピーコンストラクタが発動した場合、_hostにオブジェクトを代入することが出来ないのでprivateにして使えないようにしています。

プロパティテンプレートクラスの使い方の例
///
/// 座標情報を格納するPointクラスのX座標とY座標をプロパティテンプレートで実装する
/// Point.h
///
#ifndef _INC_POINT_H_
#define _INC_POINT_H_

#include "Property.h"

///
/// 座標を格納するクラス
///
class Point
{
 int _x;
 int _y;

 void setX(const int& val);
 int getX() const;
 void setY(const int& val);
 int getY() const;

public:
 Test::Property<Point, int> X;
 Test::Property<Point, int> Y;

 Point();
 Point(const Point& other);
 void operator=(const Point& other);
};

#endif

///
/// Point.cpp
///
#include "Point.h"

void Point::setX(const int& val)
{
 this->_x = val;
}

int Point::getX() const
{
 return this->_x;
}

void Point::setY(const int& val)
{
 this->_y = val;
}

int Point::getY() const
{
 return this->_y;
}

Point::Point()
 : X(this, &Point::getX, &Point::setX)
 , Y(this, &Point::getY, &Point::setY)
{
}

Point::Point(const Point& other)
 : X(this, &Point::getX, &Point::setX)
 , Y(this, &Point::getY, &Point::setY)
{
 *this = other;
}

void Point::operator=(const Point& other)
{
 this->X = other.X;
 this->Y = other.Y;
}

///
/// main.cpp
///
#include <iostream>
#include "Point.h"

int _tmain(int argc, _TCHAR* argv[])
{
 Point a;
 Point b = a;

 a.X = 1;
 a.Y = 2;
 b.X = 123;
 b.Y = 456;

 std::cout << "a.X = " << a.X << std::endl;
 std::cout << "a.Y = " << a.Y << std::endl;
 std::cout << "b.X = " << b.X << std::endl;
 std::cout << "b.Y = " << b.Y << std::endl;

 return 0;
}

メンバ変数にはメンバ変数のアクセッサを経由してアクセスするようにします。さらにアクセッサをPropertyクラスで隠蔽することであたかも変数だけで操作しているように見せかけます。
コピーコンストラクタの実装では、プロパティのコピーコンストラクタではなく、コンストラクタを呼び出した後にoperator=で値の代入を行います。この部分が冗長なので恰好悪いのですね。ここでthisポインタを渡す方法があれば解決できるんですが、思いつきませんでした。

出力結果
a.X = 1
a.Y = 2
a.X = 123
b.Y = 456

Point b = aのところでコピーコンストラクタが発動しますが、aとbの結果が違うことが分かります。ちゃんと期待通りに動いてくれました。

2012年12月30日日曜日

共有ライブラリを複数のプロセスから呼び出した場合のグローバル変数の振る舞い

共有ライブラリはロードしたプログラムデータはプロセス間で共有するが、インスタンスはプロセス毎に持つことを確認してみました。
実験はプロセスAとプロセスBが共有のライブラリTest.dllを参照して、グローバル変数を変更します。

ここはグローバル変数をインスタンス化して、このインスタンスのGetterとSetterをインターフェイスにして公開します。

プロセスAとBが参照するTest.dllの中身
///
/// Test.h
///
#ifndef _INC_TEST_H_
#define _INC_TEST_H_

#ifdef _TEST
 #define TEST_API __declspec(dllexport)
#else
 #define TEST_API __declspec(dllimport)
#endif

namespace Test {

TEST_API void SetValue(int val);
TEST_API int GetValue();

}

#endif

///
/// Test.cpp
///
#include "Test.h"

namespace Test {

///
/// プロセス間のメモリ共有の確認
/// プロセス毎に初期化が行われ、プロセス毎にインスタンスが生成される
///
static int _val = 0;

TEST_API int GetValue()
{
 return _val;
}

TEST_API void SetValue(int val)
{
 _val = val;
}

}

暗黙的リンクでTest.dllをロードします。エントリポイントのはじめにTest空間にあるグローバル変数の値を2に変更し、プロセスBを実行します。そのあとにグローバル変数を確認します。表示される値は2か100のどちらかになると思います。2であれば、グローバル変数のインスタンスが共有されていることになります。100であれば、プロセス毎にインスタンスが生成されていることになります。

プロセスAのエントリポイント
///
/// AMain.cpp
///
#include "Test.h"
#include <iostream>
#include <stdlib.h>

int _tmain(int argc, _TCHAR* argv[])
{
 // 初期値の表示
 std::cout << "A.exe " << Test::GetValue() << std::endl;

 // 値を2に更新
 Test::SetValue(2);

 // 別プロセスを実行
 // 別プロセスで値を100に更新している
 system("B.exe");

 // 値の表示
 std::cout << "A.exe " << Test::GetValue() << std::endl;

 return 0;
}

プロセスBのエントリポイント
///
/// BMain.cpp
///
#include "Test.h"
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
 // 値の表示
 std::cout << "B.exe " << Test::GetValue() << std::endl;

 // 値を100に更新
 Test::SetValue(100);

 return 0;
}

出力結果
A.exe 0
B.exe 0
A.exe 2

結果からプロセス毎にインスタンスが生成されていることが分かりますね。

2012年12月25日火曜日

ダイナミックライブラリのエントリポイント

ダイナミックライブラリのエントリポイントはWindows環境ならDllMainで良いけどLinux環境でどのように実現すればよいのか困っていたけどグローバル変数とコンストラクタとデストラクタを使うと似たような振る舞いを実現できます。以下はその例です。

共通ライブラリがロードされるとグローバル変数がインスタンス化されて、DLManagerのコンストラクタが呼び出されます。グローバル変数のインスタンス化はエントリポイントの開始よりも先に呼び出されるので、初期化の位置としては悪くないように思います。
アンロードの場合もエントリポイントを抜けたあとにデストラクタが呼び出されます。

共通ライブラリのロードアンロードクラス
///
/// DLManager.cpp
///
#include <iostream>

class DLManager
{
public:
 DLManager()
 {
  std::cout << "Test library start!!" << std::endl;
 }

 ~DLManager()
 {
  std::cout << "Test library end!!" << std::endl;
 }
};

///
/// グローバル空間にインスタンス化する
///
static DLManager _dlManager;

DLL内に定義されている例題クラス
///
/// Someone.h
///
#ifndef _INC_HEADER_H_
#define _INC_HEADER_H_

#ifdef _TEST
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

class TEST_API Someone
{
public:
 Someone();
 ~Someone();
 void Do();
};

#endif

///
/// Someone.cpp
///
#include <iostream>
#include "Someone.h"

Someone::Someone()
{
}

Someone::~Someone()
{
}

void Someone::Do()
{
 std::cout << "something" << std::endl;
}

エントリポイント
///
/// Main.cpp
///
#include <iostream>
#include "Someone.h"

int _tmain(int argc, _TCHAR* argv[])
{
 Someone one;
 one.Do();
 return 0;
}

出力結果
Test library start!!
something
Test library end!!

2012年12月24日月曜日

DLL内のテンプレートクラスを呼び出す方法

別DLLで定義したテンプレートクラスをmain関数で呼び出すときにリンカーに怒られました。これを躱すには明示的にテンプレートクラスをインスタンス化するという方法があるみたいです。以下はその例です。

LoggerSingletonクラスはSingletonテンプレートクラスをバインドしています。Singletonクラスは静的メンバ関数を経由してインスタンスにアクセスする機能を提供します。Log.cppの末尾で明示的テンプレートとして定義するとDLL外からも呼び出すことができます。リンクエラーの原因は単純に実装部が公開されていなかったからだけですね。つまり逆に言えば、この方法であれば実装部を隠ぺいすることができたことになり、より疎結合になったと言えます。

エントリポイント
///
/// main.cpp
///
#include <iostream>
#include "Logger.h"

int _tmain(int argc, _TCHAR* argv[])
{
 // インスタンスを取得
 Test::Logger* logger = Test::LoggerSingleton::Instance();

 // 記録
 logger->Record("Test 1");
 logger->Record("Test 2");
 logger->Record("Test 2");

 // 記録を出力
 std::cout << logger->Message();

 return 0;
}

シングルトンパターンを提供するテンプレートクラス
///
/// Singleton.h
///
#ifndef _INC_SINGLETON_H_
#define _INC_SINGLETON_H_

#ifdef _TEST
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

namespace Test {

template <typename T>
class TEST_API Singleton
{
private:
 T* _d;

public:
 ~Singleton();
 static T* Instance();

private:
 // インスタンス化をガード
 Singleton();
 Singleton(const Singleton<T>& other);
 Singleton<T>& operator=(const Singleton<T>& other);
};

}
#endif

テンプレートクラスの実装部
///
/// SingletonImp.h
///
#ifndef _INC_SINGLETON_IMP_H_
#define _INC_SINGLETON_IMP_H_

#include "Singleton.h"

namespace Test {

template <typename T>
Singleton<T>::~Singleton()
{
 delete this->_d;
}

template <typename T>
T* Singleton<T>::Instance()
{
 static Singleton<T> singleton;
 return singleton._d;
}

template <typename T>
Singleton<T>::Singleton() : _d(new T)
{
}

}
#endif

テンプレートクラスの明示的インスタンス化
///
/// Logger.h
///
#ifndef _INC_LOGGER_H_
#define _INC_LOGGER_H_

#include <string>
#include <vector>
#include "Singleton.h"

namespace Test {

class TEST_API Logger
{
private:
 typedef std::vector<std::string*> Table;

 Table _table;

public:
 Logger();
 ~Logger();
 void Record(const std::string& msg);
 std::string Message();
};

typedef Test::Singleton<test::logger> LoggerSingleton;

}
#endif

///
/// Log.cpp
///
#include "SingletonImp.h"
#include "Logger.h"

namespace Test {

Logger::Logger()
{
}

Logger::~Logger()
{
 for(Table::iterator it = this->_table.begin(); it != this->_table.end(); ++it)
 {
  // インスタンスを解放
  delete *it;
 }
}

void Logger::Record(const std::string& msg)
{
 // インスタンスをコピーして格納
 this->_table.push_back(new std::string(msg));
}

std::string Logger::Message()
{
 std::string msg;

 // メッセージの作成
 for(Table::iterator it = this->_table.begin(); it != this->_table.end(); ++it)
 {
  msg += *(*it);
  msg += "\n";
 }

 return msg;
}

// 明示的テンプレートのインスタンス化
template Test::Singleton<test::logger> LoggerSingleton;
}