Boost.MultiArrayでresize()やview()がコンパイルできない件


1つ前の記事(と言っても11ヶ月前のですがw)の解決方法です.
いえ,解決自体はもっと前にしてたのですがメモをしていなかったので.

参考:
compiler bug in msvc10 with std::copy
_HAS_ITERATOR_DEBUGGING | Microsoft Docs


これによると,MSVC2010のstd::copyはInputIteratorにinput_iterator_tagかつOutputIteratorにoutput_iterator_tag,又は両方ともrandom_access_iterator_tagのどちらかの組合せを要求しているのだそうです.
それに適合しないstd::copyの使い方をしているためコンパイルエラーになっているようです.


そしてそのチェックはITERATOR DEBUG LEVELの値によって行なわれます.
つまり,そのチェックを無効にすれば良いわけです.

#define _HAS_ITERATOR_DEBUGGING 0

これをboostヘッダをインクルードする前に定義すれば大丈夫です.


ただし,翻訳単位毎にこのITERATOR DEBUG LEVELが違うとリンクエラーが発生します.
そしてやっかいな事に,Boostのライブラリファイルも同じでなければなりません.
そのため,利用するプロジェクト及びBoostをITERATOR DEBUG LEVELが0の状態でビルドしなければならないのです.


Boostは以下の様にすれば良いです.
bjam define=_HAS_ITERATOR_DEBUGGING=0 ...


MSVCのプロジェクトはプロジェクトのプロパティからC/C++プリプロセッサ全体に定義すれば良いと思います.


と,書いておいて何ですが,この方法はあまりよろしくないですよね.
良い方法はないでしょうか….

VS2010でMultiArray::resize()が使えない?


VS2010 beta2で次のコードがコンパイルエラーになります.
VS2008 EEだと通るんですけどね.

#include <boost/multi_array.hpp>

int main(){

	boost::multi_array<int, 2> ary(boost::extents[1][2]);
	ary.resize(boost::extents[2][3]);

}

error C2665: 'std::_Copy' : none of the 2 overloads could convert all the argument types c:\program files\microsoft visual studio 10.0\vc\include\xutility 2216


まぁエラー内容は教えてくれている通りですけど.

セマフォ


Boost.Threadにセマフォが無いのでどうしようかと思いましたが,Boost.Interprocessにあるんですね.
単純にそれを使ってみました.
超シンプルです.

#include <cstddef>
#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/interprocess/sync/named_semaphore.hpp>

const std::size_t   create_threads_number   = 5;
const std::size_t   max_running_threads_number  = 3;

const char* const   semaphore_name  = "my_semaphore";


void thread_func(){

    std::cout << "Created thread: " << boost::this_thread::get_id() << std::endl;

    boost::interprocess::named_semaphore semaphore(boost::interprocess::open_only_t(), semaphore_name);

    // ここからクリティカルセクション(3スレッドまで.
    semaphore.wait();
    std::cout << " Processing: " << boost::this_thread::get_id() << std::endl;
    sleep(1);
    semaphore.post();
    // ここまで.

    std::cout << "Finished thread: " << boost::this_thread::get_id() << std::endl;

}


int main(){

    // 既にその名前のセマフォが作成されていたら困るので削除する(*1.
    boost::interprocess::named_semaphore::remove(semaphore_name);

    // 3までのセマフォを作成.
    boost::interprocess::named_semaphore(boost::interprocess::create_only_t(), semaphore_name, max_running_threads_number);

    boost::thread_group threads;
    for(std::size_t i=0; i<create_threads_number; ++i)
        threads.create_thread(thread_func);

    threads.join_all();

    boost::interprocess::named_semaphore::remove(semaphore_name);

    return 0;

}

// g++ this.cpp -lrt -lboost_thread


実行結果.
見にくい・・・.

Created thread: 0x8b53068
Processing: 0x8b53068
Created thread: 0x8b53200
Processing: 0x8b53200
Created thread: 0x8b533b0
Processing: 0x8b533b0
Created thread: 0x8b53560
Created thread: 0x8b53710
Finished thread: 0x8b53068
Finished thread: 0x8b533b0
Finished thread: 0x8b53200
Processing: 0x8b53560
Processing: 0x8b53710
Finished thread: 0x8b53560
Finished thread: 0x8b53710


同時に3つまでしかprocessingできてないです・・・よね.

googleなどで検索した時には,condition variableとmutexで自作するとかあったので・・・.
でもそっちの方が良いのかなぁと思ってみたりもします.
はたしてこれは大丈夫なのか・・・.


*1:少し乱暴ですがw

三項演算子のようなもの


とあるC言語で書かれたソースコードを見ていたのですが,こんなのがありました.


#define some_value (foo ? bar : baz)

...

void some_func(){

    some_value = qux;

}


some_valueはファイルの先頭で定義されていて,複数の関数内で使われていました.

うーん・・・凄いなぁと.
# マクロや三項演算子を左辺値にするだけではなく.


で,寝る前に何か思いついたので書いてみたのですが,何にも面白くない・・・.

クラスを使ってもっと上手くやりたかったけど眠いので日記のネタ程度にw


template<
  class T
>
const T& which(bool cond, const T& true_value, const T& false_value){

  return (cond ? true_value : false_value);

}


template<
  class T
>
T& which(bool cond, T& true_value, T& false_value){

  return (cond ? true_value : false_value);

}


int main(){

  int x = 0;
  int y = 0;

  which(true, x, y) = 5; // x = 5
  int z = which(false, x, y); // z = y = 0

}


後でBoost.Asioを使うので,そのことをメモ書きしようかなぁ.

でも恐らくネットワーク通信だけだし,サンプルにありそうなコードで物足りそうだから覚書コースだ.

staticなdestructorでファイル出力(VC)


半年振りの日記です.

やっと落ち着きました・・・.



どうも以下の挙動が理解できない.


#include <fstream>

class foo {
public:
	~foo(){
		std::ofstream fout("out.txt"); //*1
	}
};


int main(){

	static foo f; //*2
	std::ofstream fin; //*3

}


上のプログラムをVS2008EEでビルド&実行すると*1で例外が発生する.
*2と*3の行を入れ替えるとそれはなくなる.


gccではそれは起こらなかった.


staticのことをもっと詳しく知りたいけど,PLC++とかには余り詳しく書いてないんだよなぁ.


// 追記
入力ミスを修正しました.

- std::ostream fout("out.txt"); //*1
+ std::ofstream fout("out.txt"); //*1
- std::ofstream; //*3
+ std::ofstream fin; //*3

deviceの管理


DirectXで描画をする時はDeviceが必要なわけだが,どうにもこれがめんどくさい.

struct directx {
  LPDIRECT3DDEVICE9 device() const;
  // ...
};

struct texture {
  bool create(LPDIRECT3DDEVICE9 device, const std::string& file_path);
  // ...
};


なんて実装にすると,テクスチャを作る時がめんどう.

directx x;
texture tex;

tex.create(x.device(), "foo/bar.bmp");


こんなデバイスをどこにでも持っていかなきゃならない実装は嫌(めんどい)ので,裏に隠す.
private継承でis-implementation-in-terms-ofを実現(言ってみたかっただけ.
# それ以前に用語として合ってるのか・・・.


class directx {
  static LPDIRECT3DDEVICE9 device_;
protected:
  static LPDIRECT3DDEVICE9 device(){ return device_; }
  // ...
};

LPDIRECT3DDEVICE9 directx::device_ = NULL;


struct texture : private directx {
  bool create(const std::string& file_path){
    LPDIRECT3DDEVICE9 dev = directx::device();
    // ...
  }
  // ...
};


texture tex;
tex.create("baz/qux.bmp");


今までこうしてたんだけど,directxクラスの静的メンバ関数にいきなりアクセスされたりする(*1)とまずいので覆う.

あとcom_ptr<>を使ってみる.

以下の例はログの設定とか.


//TODO: directxクラスのローカルクラスへ
class directx_impl {
  LPDIRECT3DDEVICE9 device_;
  log_manager log_;
public:
  LPDIRECT3DDEVICE9 device() const{ return device_; }
  void log_level(int lv){ log_.level(lv); }
  // ...
};


class directx {
  static directx_impl& impl(){
    static directx_impl impl_;
    return impl_;
  }
protected:
  static com_ptr<IDirect3DDevice9> device(){
    return com_ptr<IDirect3DDevice9>(impl().device());
  }
public:
  static void log_level(int lv){ impl().log_level(lv); }
  // ...
};


struct texture : private directx {
  bool create(const std::string& file_path){
    auto dev = directx::device(); // 何
    // ...
  }
  // ...
};


int main(){

  directx::log_level(3); // ok
  texture tex;
  tex.create("quux/corge.bmp"); // ok

}


こんなんどうかな.
まだ実装してないけど.
これ・・・動くのか?(無責任


directx_impl::~directx_impl()が一回しか呼ばれないから,deviceの解放し忘れのチェックとかできるかも?.
staticなdeviceが一個ならだけど.


# C++0xのautoは知ってるけど,C++03のautoは知らなかったり.


余談だけど,LPDIRECT3DDEVICE9 IDirect3DTexture9::GetDevice()があるので,初期化さえしちゃえばいいんだよね.

LPDIRECT3DTEXTURE9 texture = my_create_texture("grault/garply.bmp");
LPDIRECT3DDEVICE9 device = texture->GetDevice();
device->some_func();
device->Release();

com_ptr

DirectXのCOM用のスマートポインタcom_ptr<>を書いてみた.

assertは書いてないけど.


合ってるのか不安だがw



#ifndef YUKIMI__UTILITY__COM_PTR_HPP
#define YUKIMI__UTILITY__COM_PTR_HPP

///
/// @file	/yukimi/utility/com_ptr.hpp
/// @brief	DirectXのCOM用のポインタ管理クラスの実装.
/// @author	GraighleFS
///


namespace {

#ifndef NULL
const int	NULL	= 0;
#endif

}


namespace ykm {


namespace utility {


///
/// @class	com_ptr.
/// @brief	DirectXのCOM用のポインタ管理クラス.
///			ObjectT	管理する型.
///

template<
	typename	ObjectT
>
struct com_ptr {

	typedef  ObjectT	value_type;

private:

	value_type*	pointee_;

public:

	///
	/// @brief		Constructor.
	/// @param[in]	管理するオブジェクトへのポインタ.
	/// @param[in]	com_ptrに管理を引渡した時に,参照カウントを増やすかどうか.
	/// @attention	add_ref_firstについては通常はfalseで構わない.
	///
	explicit com_ptr(value_type* ptr = NULL, bool add_ref_first = false):
	pointee_	(NULL){

		pointee_	= ptr;
		if(add_ref_first && pointee_)
			pointee_->AddRef();

	}


	///
	/// @brief		Copy-Constructor.
	///
	explicit com_ptr(const com_ptr<value_type>& org):
	pointee_	(org.pointee_){

		if(pointee_)
			pointee_->AddRef();

	}


	///
	/// @brief		Destructor.
	/// @throw		Nothrow.
	///
	~com_ptr() throw(){

		if(pointee_)
			pointee_->Release();

	}


	///
	/// @brief		Operator=().
	///
	com_ptr<value_type>& operator=(const com_ptr<value_type>& org){

		com_ptr<value_type> temp(org);
		swap(temp);
		return *this;

	}


	///
	/// @brief		Operator*().
	///
	value_type& operator*() const{

		//TODO: assert
		return *pointee_;

	}


	///
	/// @brief		Operator->().
	///
	value_type* operator->() const{

		//TODO: assert
		return pointee_;

	}


	///
	/// @brief		Operator&().
	///
	value_type** operator&() const{

		return &pointee_;

	}


	///
	/// @brief		Operator bool.
	/// @throw		Nothrow.
	///
	operator bool() const{

		return (pointee_ != NULL);

	}


	///
	/// @brief		Swap.
	/// @throw		Nothrow.
	///
	void swap(com_ptr<value_type>& other) throw(){

		value_type*	temp	= pointee_;
		pointee_			= other.pointee_;
		other.pointee_		= temp;

	}


	///
	/// @brief		管理するオブジェクトを再設定.
	/// @param[in]	管理を共有するcom_ptr.
	///
	void reset(const com_ptr<value_type>& other){

		com_ptr<value_type> temp(other.pointee_, true);
		swap(temp);

	}


	///
	/// @brief		管理するオブジェクトを再設定.
	/// @param[in]	管理するオブジェクトへのポインタ.
	/// @param[in]	com_ptrに管理を引渡した時に,参照カウントを増やすかどうか.
	/// @attention	add_ref_firstについては通常はfalseで構わない.
	///				別のcom_ptrと管理を共有する場合は,reset(const com_ptr<value_type>&);を使うこと.
	///
	void reset(value_type* ptr = NULL, bool add_ref_first = false){

		com_ptr<value_type> temp(ptr, add_ref_first);
		swap(temp);

	}


	///
	/// @brief		管理しているオブジェクトへのポインタを返す.
	/// @throw		Nothrow.
	///
	value_type* ptr() const{

		return pointee_;

	}


	///
	/// @brief		DirectXの生成メソッドに渡す時に便利なメソッド.
	///				管理しているオブジェクトを管理下からはずし,ポインタを返す.
	///
	value_type** released_ptr(){

		if(pointee_)
			pointee_->Release();
		pointee_ = NULL;
		return &pointee_;

	}


};


} // namespace utilitty


} // namespace ykm


#endif // YUKIMI__UTILITY__COM_PTR_HPP