VS2008でauto_ptrをメンバ変数にもつクラスをvectorに入れる(

std::auto_ptr をメンバ変数に持つクラスを std::vector に入れたい、そんなことありますよね?

VS2010 ならば

#include "stdafx.h"
#include <memory>
#include <vector>

class A {};

class B {
private:
	std::auto_ptr<A> a_;
public:
	B( void ) : a_( new A() ) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
	std::vector<B> bs1;
	bs1.push_back( B() ); // Bのコピーコンストラクタでエラー

	std::vector<B> bs2;
	bs2 = bs1;            // ここもBのコピーコンストラクタでエラー

	return 0;
}

なんてコードで問題ありませんが、2008だと上記コメント部分でコンパイルエラーとなります

B( const B& other ) : a_( other.a_ ) {} // otherはconstなので所有権委譲ができない

B::a_ の型を std::tr1::shared_ptr にすることでこの問題は解決しますが、なにせ shared_ptr は重いし遅い。
※一般用途では shared_ptr で問題ないパフォーマンスです。ただ、インスタンスが数百万単位になると馬鹿にならない。

では boost::ptr_vector ならばどうなるかというと

#include "stdafx.h"
#include <memory>
#include <boost/ptr_container/ptr_vector.hpp>

class A {};

class B {
private:
	std::auto_ptr<A> a_;
public:
	B( void ) : a_( new A() ) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
	boost::ptr_vector<B> bs1;
	bs1.push_back( new B() ); // ここは通る

	std::vector<B> bs2;
	bs2 = bs1;                // ここで B のコピーコンストラクタでエラー

	return 0;
}

ということになってしまいます。

ということで続きは明日

アプリケーションの初期化処理でエラーが発生しました。

ということで、今作っているアプリに C++/CLI のプロジェクトを追加し、libやらを設定した後に起動すると「アプリケーションの初期化処理でエラーが発生しました。エラーコード 0xC0000005」というのが発生。

起動時のdll読み込み処理などを見てみると、エラー発生直前と思えるのに comctl32.dll があり、それが SxS で入るdllだったのでバージョン違いか何かか?と想像。
ネットをたどると sxstrace.exe を使うと良いというのがあったので探してみると・・・無い。無い。無い。


なんと Vista 以降にしか入っていないと言うではないか(開発はXP SP3)。

しょうが無いので Vista なら sxstrace で何か解るかと思って実験してみると今度は出ない。

意味がわからない・・・

ということで、あきらめて SVN から新規に co して同等のを作ってみると今度は起動できる。

いったい何が悪かったのか両方を見比べてみると。dllのロード順が違う。同じソリューションの他のライブラリの方が先にロードされている。

両方の exe プロジェクトのリンカ設定を見ると lib の順番が違う。
一応替えてみると今度は上手くいく。

うーんこれはそういうものなのか、向こうのライブラリが悪いのか・・・
とりあえずそんなところで今日は終了。

MSXML の SAXWriter

Domを使って書き込むのではなく、SAXで何か良いのはないかと思っていたら
MSXMLに IMXWriter という SAXWriter があるではないか。
今のコードは Windows 限定だし使ってみるかーということでトライ。

// saxwritertest.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "windows.h"
#include "Objbase.h"
#import <msxml6.dll> named_guids

#include <iostream>
#include <vector>

namespace {

bool CreateStream( IStream** stream ) {
	HRESULT hr = ::CreateStreamOnHGlobal( NULL, TRUE, stream );
	return hr == S_OK;
}

} // namespace


int _tmain(int argc, _TCHAR* argv[])
{
	::CoInitialize( NULL );

	IStreamPtr stream;
	CreateStream( &stream.GetInterfacePtr() );

	try {
		MSXML2::IMXWriterPtr writer;
		HRESULT hr = writer.CreateInstance( MSXML2::CLSID_MXXMLWriter60 );
		writer->byteOrderMark = VARIANT_TRUE;
		writer->encoding	= _bstr_t( "utf-8" );
		writer->indent		= VARIANT_TRUE;
		writer->output		= stream.GetInterfacePtr();

		MSXML2::ISAXContentHandlerPtr handler = writer;
		handler->startDocument();

		wchar_t* ns( L"test" );
		wchar_t* local( L"example" );
		wchar_t* qname( L"test:example" );
		handler->startElement(
			reinterpret_cast<unsigned short*>( ns ), wcslen( ns ),
			reinterpret_cast<unsigned short*>( local ), wcslen( local ),
			reinterpret_cast<unsigned short*>( qname ), wcslen( qname ),
			NULL );

		handler->endElement(
			reinterpret_cast<unsigned short*>( ns ), wcslen( ns ),
			reinterpret_cast<unsigned short*>( local ), wcslen( local ),
			reinterpret_cast<unsigned short*>( qname ), wcslen( qname )
			);
		handler->endDocument();

	}catch(_com_error& e ){
		std::cout << e.ErrorMessage() << std::endl;
		::CoUninitialize();
		return 0;
	}

	{ // 書き込み内容を見る
		LARGE_INTEGER pos = {0, 0};
		stream->Seek( pos, STREAM_SEEK_SET, NULL );

		size_t size( 1024 );
		std::vector<byte> buffer;
		buffer.resize( size, 0 );
		unsigned long read;
	 	stream->Read( &buffer[0], size, &read );
		std::cout << &buffer[0] << std::endl;
	}

	::CoUninitialize();
	return 0;
}

で結果が

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<test:example/>
続行するには何かキーを押してください . . .

・・・おーい? xmlns が出てないよ?

と思ってネットを探っていたら バグです とか・・・

あきらめて、litexml とか xerces とか libxml とか使いましょ!

ファクトリの取得方法

うーんC++で下のようなコードの書き方がわからん・・・

import java.util.Map;

public abstract class Base {
    static Map<String, Factory> map;
    static {
        map.put("foo", new Foo.FooFactory());
        map.put("bar", new Bar.BarFactory());
    }
    
    static Base create(String target) {
        for (Map.Entry<String, Factory> entry : Base.map.entrySet()) {
            if (target.equals(entry.getKey())) {
                return entry.getValue().create();
            }
        }
        return null;
    }
    
    public abstract String getType();
}


interface Factory {
    Base create();
}

class Foo extends Base {
    static class FooFactory implements Factory {
        public Foo create() {
            return new Foo();
        }
    }
    
    public String getType() {
        return "foo";
    };
}

class Bar extends Base {
    static class BarFactory implements Factory {
        public Bar create() {
            return new Bar();
        }
    }
    
    public String getType() {
        return "bar";
    };
}

class Main {
    public static void main(String[] args) {
        Base base = Base.create("bar");
        System.out.println(base.getType());
    }
}

マラソン日記 その1

急遽来年の4月にある徳島吉野川ラソンに参加することになったので
半年で運動していない体からフルマラソンに耐えれる体にすることになりました(汗

ちなみに運動歴は

〜中学:水泳部
高校:陸上ホッケー
大学〜:何もせず

というずたずたな体なわけですな。何も運動していない期間が10年ほど。あるとすると一昨年に少し水泳をチョロチョロとやってたぐらい。幸い酒もタバコもやらないのでそういう点では健康かも。ただ体重が…ねぇ…


ということでマラソン日記。

12月頭〜
一緒に吉野川ラソンに参加しようと言われて会社の周りをぐーるぐる1,2周を隔日ぐらいに。

12/20
こりゃアカンということでとりあえず家〜吉野川大橋〜河川敷〜旧橋〜家と約8kmぐらいのコースを1時間かけて歩いたり走ったりしてゴール。
家に帰って汗を流したら急激な眠気と筋肉痛。4月に間に合うんかね…

12/21, 12/22
お休み

12/23
家〜旧橋往復〜家(約8km)をこれも一時間かけて。今回は休まずに走れた。というか休みつつ走ったら走れない気がする。

12/24, 12/25
お休み

12/26
会社の周りを一周。大丈夫か…?

12/27
お休み

12/28
ジムでひたすら一時間走る練習。風景が全く変わらないためつまらない。自分には会ってないんじゃないかな…とはいえ夜に真っ暗な道を走ることを考えればマシな気がする。

12/29
お休み

12/30
実家に帰ってるので実家近くの川の周りをぐーるぐる2周。7kmぐらい?
外走るのが久々だったせいかかなりきつい。
朝飯を食べた直後だったということもあるし、実家に帰ると必ずでる喘息の発作薬を使った後だったせいもあるかも。

12/31
お休み

ということで去年のマラソンへの記録は以上だ!
はたして半年でフルマラソン走りきれるのか!?

(*ちなみに吉野川ラソンの去年の記録によると、完走率が94%なので完走できないと残念な感じになるような。。。)