About

地図会社で働いていたプログラマ。

2012年12月16日日曜日

はじめてのAndroidアプリ。

 

はじめてのAndroidアプリ。

思ったより簡単だったね!

Screenshot_2012-12-16-22-01-10

 

ソース

// MainActivity.java
package com.example.helloworld;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
import android.widget.Button;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button button = (Button)findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TextView text = (TextView)findViewById(R.id.textView1);
text.setText("Hi, This is the very first Android app of mine!");
}
});
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}


 



// res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/textView1_text" />

<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp"
android:text="@string/button1_text" />

</RelativeLayout>

2012年12月9日日曜日

[翻訳] 64ビット環境移植における20個の問題【途中】

翻訳元サイト
20 issues of porting C++ code on the 64-bit platform
http://www.viva64.com/en/a/0004/#ID0EMEBK

概要

C++コードを32ビットから64ビット環境へ移植する際に発生し得る問題について述べる。間違ったコードとそれを正す方法を示す。また、これらの問題を診断するコード解析手法についも述べる。

序論

本稿では、32ビットから64ビット環境へ移植手順について議論する。本稿はC++プログラマ向けであるが、別プラットフォームでアプリケーションを移植する全ての人に有用な情報となるかもしれな。著者は64ビット環境移植の専門家と64ビット移植に特化したコード解析ツールViva64ツールの開発者である。

64ビット移植をする際には、他の数千以上もあるプログラムの間違いではないの新しいタイプのエラーを理解するべきである。これらは全ての開発者が経験する不可避の問題である。この記事ではそのような問題に対する準備と対策方法を示す。プロミングだけでなく全ての新しい技術は、いくつかの制限や問題を抱えている。64ビットソフトウェア開発も状況は同じである。われわれは64ビットソフトウェアがIT開発の次のステップだと知っているが、実際はほとんどのプログラマは64ビットプログラム開発に関わっておらず、これらの問題に触れる機会はない。

64ビットアーキテクチャの利点を長々と話すつもりはない。このテーマに関してはたくさんの文献があるので参照されたい。この記事の目的は、64ビットアプリケーションの開発者が直面する問題の考察し、以下を学ぶことにある。
  • 64ビットシステムで起こる典型的な問題
  • それらの理由と対応するコード例
  • エラーの修正方法
  • 64ビットプログラムの間違いを探す方法

この知識によって読者は
  • 32/64ビットシステムの違いを理解できる
  • 64ビットプログラムを開発する際に間違いを避けられる
  • デバッグやテストにかける時間を減らせることで、32ビットから64ビットへの移植をすばやく行える
  • 移植にかかる時間をより正確に見積もることができる

また、この記事の中には多くのサンプルコードが含まれているため、より深く理解するためにぜひ試していただきたい。これは読者にとって64ビットの世界の入り口となるはずだ。まずは、以降の説明の手始めにいくつかの型を思い出してほしい。


整数型とメモリサイズ型
型名型のサイズ
(32ビット)
型のサイズ
(64ビット)
説明
ptrdiff_t3264ポインタの引き算時に使用する符号あり整数型。この型はメモリサイズを保持するのに利用するまた、関数の戻り値の型としてサイズやエラー時に-1を返す。
size_t3264符号なし整数型で、sizeof()等、オブジェクトのサイズや数を保持するのに使われる。
intptr_t, uintptr_t, SIZE_T, SSIZE_T, INT_PTR, DWORD_PTR, etc3264ポインタの値を保持する整数型。
time_t3264秒単位の時間。


この記事では、これらの型を”メモリサイズ型”と呼ぶことにする。この用語はポインタを保持し、プラットフォームが32から64ビットへ変わることによってサイズが変化する全ての型を意味する。たとえばメモリサイズ型として、size_t、ptrdiff_t、全てのポインタ、INT_PTR、DWORD_PTR等がある。


32/64ビットデータモデル
ILP32
(Win*32, UNIX*32, Linux*32)
LP64
(UNIX*64, Linux*64)
LLP64
(Win*64)
ILP64
char8888
short16161616
int32323264
long32643264
long long64646464
size_t32646464
ポインタ32646464

1. ワーニングの抑制

どんなソフトウェアの書籍においても、ワーニングレベルをできるだけ高く設定されていることが推奨されている。プロジェクトをこなしてきたプログラマは経験的に、そのソフトウェアに必要な品質を判断することができる。

しかし、64ビット化においては、重大なバグを見逃すことになる可能性があるので、その考えは改め全てのプロジェクトのワーニングレベルを最高に引き上げるべき。そうしないなら、以下のようなミスを見逃すことになる。

unsigned char *array[50];
unsigned char size = sizeof(array);

// 32bit環境:sizeof(array) = 200
// unsigned charの最大値は255なので400を代入すると変数がオーバーフローする。
// 64bit環境:sizeof(array) = 400

2. 可変個の引数をとる関数

64ビット環境でNGな例
const char *invalidFormat = "%u";
size_t value = SIZE_MAX;

// 64ビット環境ではsize_tは8Byteの符号なし整数型なのでこのコードはNG
printf(invalidFormat, value);


このようなバグは64ビット化だけではない。C++言語の本質的な危険性からきている。この問題を
避けるための方法として、そのような関数の使用は避け、より安全な関数を使うことである。例えば、printfの代わりにcout、sprintfの代わりにboost::formatやstd::stringstreamである。

もし、printfやscanf系の関数を利用したい場合は、以下のマクロを使うとよい。
size_t u;

scanf("%u", &u);  // Win32
scanf("%Iu", &u); // Win64
scanf("%lu", &u); // Linux64

3. マジックナンバー

質の低いコードはマジックナンバーを含んでいる。マジックナンバーはその存在自体が危険であり、アドレス演算、オブジェクトのサイズ、ビット演算等に使われていた場合、64ビット化移植時が困難になる。

以下は64ビット化移植に影響する基本的なマジックナンバーである。


説明
4ポインタのバイト数
32ポインタのビット数
0x7fffffff32ビット符号付き整数の最大値、また32ビット型の最上ビットのマスク値として使われる
0x8000000032ビット符号付き整数の最小値、また32ビット型の最上ビットのマスク値として使われる
0xffffffff32ビット変数の最大値、またはエラー値-1として使われる

マジックナンバーは、sizeof()演算子やのマクロで置き換えるべきである。

64ビット環境でNGな例

// 1) intptr_tの動的領域確保にマジックナンバーを使用している。
//    intptr_tは32ビット環境では4byteだが64ビット環境ではは8byte
size_t ArraySize = N * 4;
intptr_t *Array = (intptr_t *)malloc(ArraySize);

// 2) 64ビット環境ではsize_tは8byte
size_t values[ArraySize];
memset(values, ArraySize * 4, 0);

64ビット環境でOKな例
// 1)
size_t ArraySize = N * sizeof(intptr_t);
intptr_t *Array = (intptr_t *)malloc(ArraySize);

// 2)
size_t values[ArraySize];
memset(values, ArraySize * sizeof(size_t), 0);

4. int型数値のdouble型変数への格納

32ビット環境では、intが4byteでdoubleが8Byteのためint値をdouble型変数に格納しても問題なかった。64ビット環境では、以下の図のとおりsize_t等の変数が8byteになるため変数がオーバーフローする可能性がある。
// 1) 32ビット これはOK
size_t val1 = SIZE_MAX; // size_tはunsigned intと同じで4バイト
double val2 = UINT_MAX;

// 2) 64ビット これはNG
size_t val1 = SIZE_MAX; // size_tは4バイトとなる
double val2 = UINT_MAX; // オーバーフロー

5. ビットシフト

64ビット環境のことをあまり考えずにビットシフトをすると、以下のような問題に陥ることがある。

64ビット環境でNGな例
ptrdiff_t SetBitN(ptrdiff_t value, unsigned int bitNum)
{
// 1はint型リテラルなので、4Byteの範囲しか値を取ることができないため、
// 8Byte変数のビットシフトができない可能性がある
ptrdiff_t mask = 1 << bitNum;

return value | mask;
}

ここで何が起きているかというと、
以下の図のように32Bit変数に1の値が入っている場合、32回ビットシフトすると桁があふれて値が0となってしまう。一方、64Bit変数は32回以上ビットシフトしても値があふれることはない。



64ビット環境でOKな例
// 数値1のptrdiff_t変数を生成する
ptrdiff_t mask = ptrdiff_t(1) << bitNum;

ptrdiff_t mask = CONST3264(1) << bitNum;

6. ポインタアドレスの保存

32ビット環境では、intとポインタのサイズがともに4Byteであるため、ポインタをintにキャストしてアドレス演算をすることができた。64ビット環境では、メモリサイズ型のuintptr_t型を使うと別アーキテクチャへ移植できて良い。

64ビット環境でNGな例

1) char *p;
p = (char *)((int)p & PAGEOFFSET); // ポインタをintにキャストしてはいけない

// mallocの戻り値(void *)をDWORD(unsigned int)にキャストしてはいけない
2) DWORD tmp = (DWORD)malloc(ArraySize);

64ビット環境でOKな例

1) char *p;
p = (char *)((intptr_t)p & PAGEOFFSET);

2) DWORD_PTR tmp = (DWORD_PTR)malloc(ArraySize);

64ビット環境でも少ないメモリしか利用していない時は再現しないので、非常に発見が困難なバグになり得る。上記NG例はメモリ使用量が4GBを超えた時点で、動作は未定義となる。

8. 配列のキャスト

64ビット環境では、配列のキャストが危険な場合とそうでない場合がある。
int array[] = {1, 2, 3, 4};
enum ENumbers {ZERO, ONE, TWO, THREE, FOUR};

// 安全なキャスト
ENumbers *enumPtr = (ENumbers *)(array);
cout << enumPtr[1] << " ";

// 危険なキャスト
size_t *sizePtr = (size_t *)(array);
cout << sizePtr[1] << endl;

// 32ビットプログラムでの出力結果: 2 2
// 64ビットプログラムでの出力結果: 2 17179869187


ここで何が起こっているというと、以下の図のように64ビット環境でint、enum型は4Byteだがsize_t型は8Byteのためである。

9. メモリサイズ型を引数に持つvirtualなメンバ関数

virtualなメンバ関数をもつ多くなクラスがある場合、不注意でメモリサイズ型を別の型と混同して使ってしまうことがある。32ビット環境はこれでも問題ない。例えば、基底クラスのvirtualなメンバ関数にsize_tを使い、派生クラスにはunsignedを使ったとしよう。64ビット環境では問題が生じてしまう。

しかし
class CWinApp {
...
virtual void WinHelp(DWORD_PTR dwData, UINT nCmd);
};
class CSampleApp : public CWinApp {
...
virtual void WinHelp(DWORD dwData, UINT nCmd);
};

ここでアプリケーション開発のライフサイクルを考えてみよう。例えば、Microsoft Visual C++ 6.0を使ったCWinAppクラスのWinHelp関数を以下のようにプロトタイプ宣言したとする。
virtual void WinHelp(DWORD dwData, UINT nCmd = HELP_CONTEXT);

派生クラスのCSampleAppでこの関数をオーバーライドすることに特に問題はない。その後、このプロジェクトはMicrosoft Visual C++ 2005にポーティングしたとする。

FC2→Bloggerに移行する際にやったこと


※以下の設定メモは2012/12/09時点です。Bloggerがバージョンアップすれば手順が変わる可能性があります。

  • FC2からブログ記事をBloggerにインポートする
以下のサイトの手順で問題なく移行可能
http://ss117935.blogspot.jp/2012/05/fc2-blogger.html
  • デザインテンプレートを設定する
Blogger Templatesのページから好きなテンプレートをダウンロードし、以下の手順でBloggerに設定する。
  1. ダウンロードしたページを解凍し、“テンプレート名.xml” ができる
  2. Bloggerの管理ダッシュボード→「テンプレート」→「バックアップ/復元」をクリック
  3. 「ファイルを選択」をクリックし、Bloggerに、“テンプレート名.xml”をアップロードする

  • Google Code Prettifyを導入してコードのシンタックスハイライトをする
Bloggerの管理ダッシュボード→「テンプレート」→「HTMLの編集」を開き、以下のコードをheadタグ内のどこかに挿入する。すると、GoogleのCDNからjquery, prettifyを取得して<pre class=”prettyprint”></pre>内のコードをシンタックスハイライトしてくれる。
<!-- jquery 1.7.2 -->
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js' type='text/javascript'/>

<!-- Google Prettify -->
<link href='http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css' rel='stylesheet' type='text/css'/>
<script src='http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js' type='text/javascript'/>
<script type='text/javascript'>
$(function() {
  prettyPrint();
});
</script>
</head>

  • table要素のスタイルを設定する
Bloggerの管理ダッシュボード→「テンプレート」→「カスタマイズ」→「アドバンス」→「CSSを追加」をクリックし、以下のコードを追加する

table {
    border: 1px #E3E3E3 solid;
    border-collapse: collapse;
    border-spacing: 0;
}

table th {
    padding: 5px;
    border: #E3E3E3 solid;
    border-width: 0 0 1px 1px;
    background: #F5F5F5;
    font-weight: bold;
    line-height: 120%;
    text-align: center;
}
table td {
    padding: 5px;
    border: 1px #E3E3E3 solid;
    border-width: 0 0 1px 1px;
    text-align: center;
}

参考にさせて頂いたページ

クリボウのBlogger Tips
http://www.kuribo.info/

2012年12月8日土曜日

Photosynth - from my beloved room in Osaka

Photosynthでバルコニーからのパノラマ写真を作ってみた☆



Open Street Map - Haiti

Maybe you have never heard about it so I am gonna explain a little bit about what Open Street Map (OSM) is first. Open Street Map is maps for open source where anybody can join and create a portion of maps and use it for free.You might wonder if it is the same as Google Maps but it's different. Google maps is actually NOT open source, you can use it for free as well though. The whole contents of Google maps are licensed by Google and you have to pay certain amount of money if you want to use it for the purpose that Google may want that to happen without being paid (i.e. for commercial use).

So real open source map is only Open Street Map not Google maps, Yahoo, Bing maps and any other online maps. First I got to knew OSM is time when I participated in Open Source Conference Tokyo 2010 on August 11th. I joined a session about OSM and the guys out there got me interested by the following awesome video.

OpenStreetMap - Project Haiti from ItoWorld on Vimeo.


The video illustrates how the maps for Haiti was created over time right after the earth quake occurred. From what I've heard, one of the community members of OSM came up with that idea in oder to help Haitian people. The best part is not only lots of people in the community participated (what we call Mapper) but ito made awesome video to encourage more people get interested in the activities. Here is another video.

Open Street Map 2008 Map Edits from Peter Dunn on Vimeo.


I got soooo interested in OSM and came to think what I can do something for them. I've heard it's so easy to become a mapper so I am gonna register the OSM user and draw some maps around my place for starters.

Hourai Bridge





C#でPOSTメソッドを使用する

@ITの記事のC#でPOSTメソッドほぼ写経。

WebRequest/WebResponseクラスでPOSTメソッドによりデータを送信するには?
http://http://www.atmarkit.co.jp/fdotnet/dotnettips/318webpost/webpost.html

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;

class Program
{
    static void Main(string[] args)
    {
        // POSTする対象のURL
        string url = "http://www.rarejob.com/login/top.php?mode=off&";
        // POSTメソッドで渡すパラメータ
        string param = "";

        // Dictionaryオブジェクト
        var dic = new Dictionary<string, string>();
        dic["USER_ID"] = "メールアドレスを指定";
        dic["PASSWORD"] = "パスワードを指定";

        // POSTメソッドのパラメータ作成
        foreach (string key in dic.Keys)
            param += String.Format("{0}={1}&", key, dic[key]);

        // paramをASCII文字列にエンコードする
        byte[] data = Encoding.ASCII.GetBytes(param);

        // リクエスト作成
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = data.Length;

        // ポストデータをリクエストに書き込む
        using (Stream reqStream = request.GetRequestStream())
        reqStream.Write(data, 0, data.Length);

        // レスポンスの取得
        WebResponse response = request.GetResponse();

        // 結果の読み込み
        string htmlString = "";
        using (Stream resStream = response.GetResponseStream())
            using(var reader = new StreamReader(resStream, Encoding.GetEncoding("Shift_JIS")))
            htmlString = reader.ReadToEnd();

        // 結果の出力
        Console.WriteLine(htmlString);

        Console.Write("Press enter to end:");
        Console.ReadLine();
    }
}

definition: Sama, Kun, Chan, San

This is a response to Samsan's question about how to use Sama, Kun, Chan and San when you call your japanese people. Here is general definitions for each word.

Sama is used to call a person in the most respective manner. It's just like Sir or Madam in English. If you work for a company, you should call your customers their name with Sama.

Kun is used to call a male kid or a male person at the same or yonger age than you. 

Chan is similar to Kun but generally for Girls.You may use Chan for a both male and female kid, or female person at the same or yonger age. My mom calls me Yuki-kun or Yuki-chan.

San is useful word. You can use it for anyone in most of the situations. In fact, I use it all the time at work, to call my colleagues, boss, and my friends.

Without any one of those would be ok for only your very close friends, subordinates or family members. It may sound strong and intimate. If you say so to the person you don't know well, you would be regarded as a rude person.So be careful to use if you are not a native japanese speaker.

Javaの暗黙型変換

Javaの暗黙的型変換の基本ルール

このルールは算術演算時、メソッド・コンストラクタの引数として使われるときに適用される。
byte → short → int → long → float → double
char → int → long → float → double

class Conv1 {
    public static void main(String[] args) {
        Conv1 c = new Conv1();

        byte b = 97;
        // コンパイルエラー。byte → charの暗黙の型変換はされない。
        //c.convChar(b);

        // 出力 97
        c.convShort(b);

        // コンパイルエラー。char → shortの暗黙の型変換はされない。
        //c.convShort('a');

        // 出力 97
        c.convInt('a');

        // 出力 97.0
        c.convDouble('a');
    }

    void convChar(char c) {
        System.out.println(c);
    }

    void convShort(short s) {
        System.out.println(s);
    }

    void convInt(int i) {
        System.out.println(i);
    }

    void convDouble(double d) {
        System.out.println(d);
    }
}

C#の暗黙的型変換の基本ルール

sbyte → short → int → long → float → double → decimal
byte → short, ushort → int, uint → long, ulong → float → double → decimal
char → ushort → int, uint → long, ulong → float → double → decimal

EF英語能力指数ランキング

EF英語能力指数の世界ランキング
http://www.efjapan.co.jp/epi/ef-epi-ranking/?tc=IQ

1位 ノルウェー
2位 オランダ
3位 デンマーク
  :
9位 マレーシア
12位 香港
13位 韓国
14位 日本
25位 台湾
29位 中国
39位 ベトナム
42位 タイ

調査のサンプル
200万人以上のオンラインの英語テストを受けた人

EF EPI


サインイン, サインオン, サインアップ, ログイン, ログオンの違いって何?

気になったのでいろいろなソースから調べてみた。結論だけ見たい人は、このポストの一番下を見てください。


はてなの質問フォーラム


ログオンとログインの違いを教えてください
http://q.hatena.ne.jp/1055836312

各単語とその反対語。これは英語をみれば明らか(インvs.アウト, オンvs.オフ等)
単語 反対語
サインインサインアウト
サインオンサインオフ
サインアップ
ログインログアウト
ログオンログオフ

  • 英語のinは「~に入る」という意味があるので、会員制サイト等で使用される。一方onは「~に接触する」、「~に沿う」という意味があるので、OSを立ち上げるという行為等に使用される。
  • UNIX系ではログイン、Windows系ではログオン。
  • CPUによる処理がどこで行われるかによって使い分ける。計算を目の前のコンピュータが行う場合は、ログオン。計算をネットワークの向こうのコンピュータが行う場合はログイン。


自分の英語の先生の回答


単語意味
サインインTo go inside your account, 自分のアカウントに入る
サインオンTo put your signature in a piece pf paper or book, 書類や本にサインをする
サインアップTo make/create an account, アカウントを作成する
ログインサインインと同じ
ログオンTo visit a website, ウェブサイト二訪問する


海外のサイトで検索した結果


What is the difference between "sign in" and "log in" and how websites choose one VS. the other?
http://www.quora.com/What-is-the-difference-between-sign-in-and-log-in-and-how-websites-choose-one-VS-the-other
  • 元々はメインフレームの時代にLog on/ Log offが使われていたが、パソコンとインターネットの発展により、Sign in/ Sign outがより一般的になった。そしてやがてLog in/ Log outへと変わっていった。LogとSignは本質的には同じ意味だが、私にはLogは専門用語に聞こえ、Signは現代的に聞こえる。
  • 私にはSign inは昔のAOLのダイアルアップ回線を思い出させる。Log inは90年代に大学で使っていたコマンドラインのUIを思い出させる。あまり違いは無いのではないか?
  • Sign inはイギリス英語から来た言葉だと思っていた
  • 親しみがある言葉が一番だと思う。だから一番しっくりくる言葉をつかったらいい。(Google, Amazon, Yahoo, Bing, TwitterはSign In/Up/Outを使っていて、FacebookはSign upとLoginの両方を使用している。)

ASP.NET Forum - log-in vs. sign-in vs. sign-on vs. log-on?
http://forums.asp.net/t/1505578.aspx/1
  • 違いは無いと思う。ShutdownとShutupみたいなもの
  • ただの言葉の違い。例えば、Windows Vistaではガジェットと呼ぶものをMac OS Xではウィジェットと呼んでいる。本質的には同じものを意味しており、ただの言い方のちがい。


自分なりの結論


Sing In/Out/On/OffとLog In/Out/On/Offは同じ意味であり、どれを使っても間違いということはない。人によって受ける印象はさまざまであり、Log系はUNIX、コマンドラインUI等のGeeky(コンピュータオタク)っぽい印象を受けるのに対し、Sign系はWindowsやダイアルアップ回線を連想させる等やや一般ユーザー向けの印象。

C#とC++でXMLをパースするサンプルソース比較

パースするXML


<osm generator="CGImap 0.0.2" version="0.6">
 <bounds maxlat="34.6669570" maxlon="135.4578320" minlat="34.6642090" minlon="135.4537220">
  <node changeset="8937729" id="288188103" lat="34.6691643" lon="135.4618170" timestamp="2011-08-06T12:45:02Z" uid="151227" user="MaryHiroshige" version="5" visible="true">
  </node>
  <node changeset="894707" id="325609282" lat="34.6611820" lon="135.4492029" timestamp="2009-04-22T09:07:45Z" uid="35930" user="Show-ichi" version="2" visible="true">
   <tag k="created_by" v="Merkaartor 0.12"></tag>
  </node>
 </bounds>
</osm>

C#のソース

// Program.cs
using System;
using System.Diagnostics;

namespace yukinarit.osm
{
 class Program
 {
  static void Main(string[] args)
  {
   Stopwatch sw = new Stopwatch();
   sw.Start();

   try
   {
    // パーサークラス
    OsmParserosmParser = new OsmParser();
    // 読み込み
    OsmParser.Load(@"Osm\map.osm");

    // 読み込んだXMLから"yukinarit"の値をもつデータを検索する
    var node = osmParser.SearchNodeByUser("yukinarit");
    Console.WriteLine(node);
   }
   catch (Exception ex)
   {
    Console.WriteLine(ex.Message);
   }

   sw.Stop();
   Console.WriteLine("-----Program Ended-----\n");
   Console.WriteLine("Elapsed Time: {0}", sw.Elapsed);
   Console.ReadLine();
  }
 }
}

// OsmParser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;

namespace yukinarit.osm
{
 class OsmParser
 {
  public OsmParser()
  {
   xmlDoc = new XmlDocument();
   nodes  = new List<OsmNode>();
  }

  public void Load(string path)
  {
   xmlDoc.Load(path);

   foreach (var e in xmlDoc.DocumentElement.SelectNodes("node"))
   {
    XmlNode enode = e as XmlNode;
    if (enode == null)
     continue;

    OsmNode node = new OsmNode();
    node.id   = Convert.ToInt32(enode.Attributes["id"].Value);
    node.lat  = Convert.ToDouble(enode.Attributes["lat"].Value);
    node.lon  = Convert.ToDouble(enode.Attributes["lon"].Value);
    node.user = enode.Attributes["user"].Value;

    this.nodes.Add(node);
   }
  }

  public OsmNode SearchNodeByUser(string user)
  {
   var queryUser = from node in nodes
    where node.user.Equals(user)
    select node;

   return queryUser.ToList()[0];
  }

  private XmlDocument xmlDoc;
  private List<OsmNode> nodes;
 }
}

// OsmNode.cs
using System;
using System.Collections.Generic;

namespace yukinarit.osm
{
 class OsmNode
 {
  public int? id;
  public double? lat;
  public double? lon;
  public string user;
  public Dictionary<string, string> attr = new Dictionary<string,string>();

  public override string ToString()
  {
   return String.Format("<node id={0} lat={1} lon={2} user={3} />",
    id, lat, lon, user);
  }
 }
}

C++のソース

// ParceOsm.cpp
#include "stdafx.h"
#include "OsmParser.h"

int _tmain(int argc, wchar_t* argv[])
{
 using namespace std;
 using namespace yukinarit::osm;

 time_t start = clock();

 try
 {
  // パーサークラス
  OsmParser osmParser;
  // 読み込み
  osmParser.Load("Osm\\map.osm");

  // 読み込んだXMLから"yukinarit"の値をもつデータを検索する
  auto node = osmParser.SearchNodeByUser("yukinarit");
  cout << node.ToString() << endl;;
 }
 catch (const std::exception &ex)
 {
  cout << ex.what() << endl;
 }

 time_t end = clock();
 cout << "-----Program Ended-----\n";
 cout << "Elapsed Time: " << (end - start) << endl;
 cin.get();
 return 0;
}

// stdafx.h
#pragma once
#include "targetver.h"
#include <tchar.h>
#include <time.h>

#include <iostream>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <algorithm>
#include <boost/property_tree/xml_parser.hpp>

// OsmParser.h
#pragma once
#include "stdafx.h"
#include "IParser.h"
#include "OsmNode.h"

namespace yukinarit
{
 namespace osm
 {

  class OsmParser
  {
  public:
   OsmParser() {};
   virtual ~OsmParser() {};

   virtual void Load(const std::string &path) override
   {
    using namespace boost::property_tree::xml_parser;
    using boost::property_tree::ptree;

    boost::property_tree::xml_parser::read_xml(path, pt, 0, std::locale("japanese"));

    ptree &osm = pt.get_child("osm");
    for (auto e = osm.begin(), end = osm.end(); e != end; e++)
    {
     if ((*e).first != "node")
      continue;

     OsmNode oNode;
     oNode.id =   (*e).second.get<int>("<xmlattr>.id");
     oNode.lat =  (*e).second.get<double>("<xmlattr>.lat");
     oNode.lon =  (*e).second.get<double>("<xmlattr>.lon");
     oNode.user = (*e).second.get<std::string>("<xmlattr>.user");

     nodes.push_back(oNode);
    }
   };

   virtual OsmNode SearchNodeByUser(const std::string &user)
   {
    using namespace std;

    auto found = find_if(nodes.begin(), nodes.end(), [&](const OsmNode &n) {
     return (n.user == user);
    });

    if (found != nodes.end())
     return *found;

    return OsmNode();
   };

  private:
   boost::property_tree::ptree pt;
   std::vector<OsmNode> nodes;
  };

 }
}

// OsmNode.h
#pragma once
#include "stdafx.h"

namespace yukinarit
{
 namespace osm
 {
  class OsmNode
  {
  public:
   OsmNode() : id(0),
   lat(0.0),
   lon(0.0),
   user(""),
   attr() {};
   virtual ~OsmNode() {};

   virtual std::string ToString()
   {
    std::stringstream s;
    s << "<node id=" << id << " lat=" << lat << " user=" << user << " />";
    return s.str();
   };

   int id;
   double lat;
   double lon;
   std::string user;
   std::unordered_map<std::wstring, std::wstring> attr;
  };

 }
}

new, mallocでサイズ0の領域を確保する

new, mallocでサイズ0の領域を確保するとどうなるかの実験
実行環境はVC10, Windows7 x64

#include <iostream>
#include <stdlib.h>

int main()
{
using namespace std;

try
{
// mallocでサイズ0の領域を確保する
unsigned char *buffMalloc = (unsigned char *)malloc(0);
cout << "malloc ptr => " << (intptr_t)buffMalloc << endl;

// newでサイズ0の領域を確保する
unsigned char *buffNew = new unsigned char[0];
cout << "new ptr => " << (intptr_t)buffNew << endl;

}
catch (const exception &ex) { cout << ex.what(); }
catch (...) {}

cin.get();
return 0;
}

実行結果 サイズ0が確保されて、そのポインタが返される。
malloc ptr => 5187096
new ptr => 5188072

VCでメモリリーク箇所をログに出力する方法


以下のブログにあるようにMSVC CRTのメモリリーク検知機能でVisual Studioのデバッグ出力ウィンドウにリーク箇所を出力可能。このメッセージをログファイルに出力する方法を調べたのでメモ。

備忘録 - [Windows] CRT のメモリリークデバッグ -
http://limejuicer.blog66.fc2.com/blog-entry-14.html

// STLやBoost等ヘッダはnewの置き換えによってコンパイルエラーが出ることが
// あるので、先にインクルードしておく
#include <vector>

// メモリリーク検知のための必要なヘッダ、定義
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define new ::new(_NORMAL_BLOCK, __FILE__, __LINE__)

int main()
{
    // プログラム終了時に自動でメモリリーク箇所を出力する設定
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

    // メモリリーク
    int *val = new int[3];
    val[0] = 0;
    val[1] = 10;

    return 0;
}

するとデバッグ出力ウィンドウこんな感じで、リーク箇所のソース名、行数、ダンプを出力可能。


次にVCのCRTにはこのデバッグ検知時の処理をフックするイベントハンドラを登録する_CrtSetReportHookW2というAPIがあり、このコールバック関数でログファイルに出力できる。まず、_CrtSetReportHookW2とそのイベントハンドラのシグニチャは以下のとおり。
// 第一引数modeには、_CRT_RPTHOOK_INSTALLか,_CRT_RPTHOOK_REMOVEを指定
// 第二引数には、イベントハンドラへのポインタを指定する
int _CrtSetReportHook2(int mode, _CRT_REPORT_HOOK myHookFunction);

// イベントハンドラのプロトタイプ
int myHookFunction(int reportType, char *message, int *returnValue)

こんな感じでコンソールやログファイルに出力できる。
// STLやBoost等ヘッダはnewの置き換えによってコンパイルエラーが出ることが
// あるので、先にインクルードしておく
#include <vector>
#include <iostream>
#include <Windows.h>
#include <cstdio>

// メモリリーク検知のための必要なヘッダ、定義
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define new ::new(_NORMAL_BLOCK, __FILE__, __LINE__)

/// <summary> CRTメモリ検知イベントハンドラ </summary>
/// <param name="reportType"> 処理タイプ </param>
/// <param name="message"> CRTからの出力メッセージ </param>
/// <param name="returnValue">  </param>
/// <returns> TRUE: _CrtSetReportHookを呼び出さない, FALSE: 呼び出す  </returns>
int __cdecl myHookFunction(int reportType, char *message, int *returnValue)
{
    switch (reportType)
    {
    case _CRT_ASSERT:
    {
        break;
    }
    case _CRT_WARN:
    {
        // メモリリークの場合は。ここで、自分のログ出力関数でファイル出力すれば良い。
        // このサンプルではコンソールに出力する。
        printf("%s\n", message);
    break;
    }
    case _CRT_ERROR:
    {
        // assert等が呼ばれた場合
        break;
    }
    default:
    {
        break;
    }
    // FALSEを返すと_CrtSetReportHookで登録したハンドラを呼び出す。
    return FALSE;
}

int main()
{
    // プログラム終了時に自動でメモリリーク箇所を出力する設定
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

    // 第一引数には、_CRT_RPTHOOK_INSTALL(ハンドラ追加)か_CRT_RPTHOOK_REMOVE(ハンドラ削除)を指定
    // 第二引数には、イベントハンドラを指定する
    _CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, myHookFunction);

    // メモリリーク発生
    int *val = new int[3];
    val[0] = 0;
    val[1] = 10;

    return 0;
}

出力結果
c:\memoryleak1\memoryleak1.cpp(61) :{70}
normal block at 0x00575E90, 12 bytes long.

Data: <            > 00 00 00 00 0A 00 00 00 CD CD CD CD

Object dump complete.