2010-12-31

日記

今日は、素晴らしく風情のある雪が降った。もっとも、北のほうに行くと、風情どころではなく迷惑な雪になってしまっているのだろう。

ともかく、今年も最後の日になってしまった。年越しそばをつくる為に、午後二時頃、いつも麺を安く売っている、とある店に買いに行ったところ、なんと売り切れであった。去年は、夕方に行ってもまだ残っていたのだが、今年はどうしたことだろう。仕方がないので、唯一残っていた、にしん蕎麦セットを、330円で買ってきた。麺と、にしんと、だしと、刻みネギが入っているので、それなりに便利だ。

甘酒を作るために、酒粕も買ってきた。

また、今年もうまい餅が手に入った。今年も、近所の餅屋でバイトをしたのだ。その代償は疲労と筋肉痛なのだが。何しろ、今年はずっとPCの前に座ってC++の規格書をにらみ暮らしていたので、運動不足だったのだ。

とりあえず、これで新年を迎える準備はできた。来年はC++の参考書を完成させなければ。

2010-12-30

まじかよ

いまさらrange-based forに対する変更を真面目に議論してる。今さら変更を加えるぐらいなら、もう今回は廃止したほうがいいんじゃないか。

Old New Thing: エスパーデバッグ:ファイルをクリップボードにコピーしてペーストしたら、昔のファイルが現れた

Psychic debugging: When I copy a file to the clipboard and then paste it, I get an old version of the file - The Old New Thing - Site Home - MSDN Blogs

ある顧客が、以下のような不思議な質問をしてきた。

あるコンピューターから別のコンピューターに、ネットワーク越しにテキストファイルをコピーしたんだけどさ、コピーが終わってネットワークディレクトリーをみてみたら、まあ、たしかに同じ名前のファイルはあるんだけどさ、タイムスタンプがまるで違っているわけよ。不思議に思ってファイルを開いてみると、コピーしたファイルとは違うんだ。何故か、昨日のファイルなんだな、これが。今日の変更が含まれていないんだよ。俺はまだ、画面上にコピー元とコピー先のフォルダを開いてるし、もちろん、コピーしたファイルは、ちゃんと変更したものであって、バックアップディレクトリのヤツじゃない。

も一度やってみたんだけどさ、やっぱ古いファイルがコピーされる。よく分からんけど、ドラッグ&ドロップを使ったら、問題はない。Ctrl+CとCtrl+Vを使った時だけ問題が起こる。何とかしてくれ。

これは実に訳の分からない問題だ。ひとつの可能性としては、顧客は間違って以前のバージョンのフォルダー(訳注:Volume Shadow Copyによるもの)からコピーしているのかもしれない。さらに別の仮説を立てる前に、顧客が追加情報を送ってきた。

何か問題を絞り込めた気がする。俺のインストールしてるクリップボードツールとなにか関係があるんだ。ツール使ってなければ、問題はないみたい。なんでツールを使ってたら、エクスプローラーはがタイムマシーンみたいな事をしてくれるんだ? この古いファイルは、パソコンの中にないんだけど、エクスプローラーはどっから取ってきてんだ?

他のMS社員は、I/Oトレースログを取るなどして、問題を調査した。興味深いことに、I/Oトレースでは、エクスプローラーはコピー元とコピー先のファイルを開いて、コピー先に対してWriteFile呼び出しを多数発行しているのに対し、コピー元に対して、ReadFileを一切呼び出していないのであった。「以前のバージョン」も確認してみたが、「以前のバージョン」のファイルは存在しなかった。まるで、無からファイル内容を生成しているようであった。

他のMS社員が次第に調査を諦める中、突然、僕の頭は震え、トランス状態に陥った。僕のエスパー能力が、勝手に喉から声を発した。それは一瞬の出来事で、僕は眼を閉じて、すぐさま現実世界に戻ってきた。さて、僕はぶっきらぼうに、以下のようにタイプした。未だに返事を覚えているのだ。

私のエスパー能力によると、このクリップボードプログラムは、クリップボードの中身を仮想化している。つまり、クリップボードの中身を勝手に書き換えている。そして、ファイルに対するクリップボードのペースト操作に対し、元の中身に差し戻そうとして、失敗している。

クリップボード拡張ユーティリティを調べると、古いクリップボードの中身を記録する機能を提供している。MS Officeクリップボードに似た機能だ。I/O操作の中に、最終アクセス日時へのクエリーが含まれていた。

問題はこれだ。

Windows Vistaからは、最終アクセス日時はデフォルトでアップデートされなくなった。どうやらプログラムは、ファイルがアクセスされていないという情報から、ファイルが更新されていないと判断し、ファイルの中身を、内部のキャッシュから作り出しているのだ。この問題を手っ取り早く解決するには、最終アクセス日時のかわりに、最終更新日時を使うとよい。

やれやれ、私のエスパー能力が正しいということを、またもや証明してしまった。ところで、エスパー能力が正しいということは、代償であるということに気がついた。以前より、さらに大勢の人々が、不思議な問題をデバッグしてくれと頼み込んでくるようになったのだ。

ちなみに、最終アクセス日時がデフォルトでアップデートされなくなった理由は、NTFSのパフォーマンス向上のためである。そもそも、最終アクセス日時の精度は、一時間らしい。

自炊店なるものが出てきたらしいが

そもそも、出版業界が電子書籍を真面目に提供していれば、今頃あんなサービスが出てくるわけがない。何も難しいことはいっていないのである。連番の画像ファイル集で十分だ。いまだにそのような媒体の電子書籍を提供できていないから、あの手のサービスが現れてしまうのだ。

そもそも、電子書籍という名称からしておかしい。E-Mail(電子手紙)は、単にメール(手紙)と呼ばれるようになった。電子書籍も、近いうちに、単に本と呼ばれるようになるだろう。もっとも、いまだにまともな電子書籍がない日本では、もうしばらくかかるだろうが。

2010-12-29

マルチスレッドとデータ競合をまともに規定するとユークリッドの原論になる

C++0x Memory Model 第0回 - メモリモデルとは何か
C++0x Memory Model 第1回 - 1.9 Program execution

だいたい2300年ぐらい前に、ユークリッドという原理主義者が、原論という本を書いた。原論では、実に当たり前で、わざわざ言うまでもないことを説明している。例えば、「点とは大きさのない位置のことである」とか、「線とは幅のない長さのことである」などといったどうでもいい定義や、「任意の点から任意の点に、直線を引くことができる」などといった当たり前すぎる公理の類である。原論が日本に入ってきたのは、1730年代のことであったが、このような当然の事柄を延々と羅列しただけの本を見た当時の日本の和算学者は、一笑して無視したという。

しかし、このような定義と公理の羅列は、やはり重要なのだ。しかし、それを真面目にやると、プログラミングの参考書ではなくなってしまう。一般のプログラマが参考書に求めることは、このような原理主義的な定義の列挙ではなく、スレッドや同期処理ライブラリの使い方だろう。

2010-12-27

アクセス宣言について解説すべきか

アクセス宣言という項目を独立して立てて、解説をすべきだろうか。

アクセス宣言は、batavia会議の結果、削除された。deprecatedではない。削除されたのだ。したがって、アクセス宣言という用語自体が、もはやC++には相応しくない。

アクセス宣言が提供していた機能は、using宣言で行える。たとえば、以下のようなクラスがあるとして、

class Base
{
    int value ;
public :
    int get() const { return value ; }
    void set( int value ) { this->value = value ; }
} ;

このBaseクラスからprivateで派生したいとする。ただし、Base::getだけはpublicで提供したい。その場合に、using宣言を使って、以下のように書くことができる。

class Derived : private Base
{
public :
    using Base::get ;
} ;

これにより、Base::valueやBase::setをprivateにしながら、Base::getだけをpublicにすることができる。

現実に必要になる例としては、operator newやoperator deleteのオーバーロードをしている基本クラスからprivate派生したクラスを、クラス外からnewさせたい場合などが当てはまる。

また、オーバーロード解決の候補関数にしたい場合も考えられる。

struct Base
{
    void f( int ) { }
} ;

struct Derived : Base
{
    void f( double ) { }
} ;

int main()
{
    Derived d ;
    d.f( 0 ) ; // call Derived::f(double)
}

クラスメンバーの名前探索では、派生クラスのメンバーに、目的の名前が見つかった場合は、その時点で名前探索を打ち切る。つまり、基本クラスのメンバー名が見つかることはない。そのため、Base::fが呼ばれることはない。これも、using宣言を使って解決できる。

問題は、この機能は、一般にあまり知られているとは言いがたいし、おそらく現実のプログラミングでは、知らなくても全く問題ないだろう。using宣言で基本クラスのメンバー名を派生クラスのスコープの持ってくるというのは、まず必要にならないからだ。

これを、わざわざ独立して解説すべきなのか。

2010-12-26

鬼を笑わせる

さて、今年も残りわずかとなった。そこで、今年も鬼を笑わせてみようと思う。

まず、PCの未来を予想してみる。

CPUの性能は、なにかすごい技術革新がない限り、あまり期待できないだろう。たしかに、より多くのコアやGPU内蔵といった未来はある。しかし、CPU自体のパフォーマンスの向上は、近年、実にわずかである。

そもそも、CPUのパフォーマンスを、最大限に使う必要がある状況も、今ではほとんど存在しない。ブラウザはそれほど重くはない(ただしIEとFirefoxをのぞく)。PCゲームのパフォーマンスは、ほとんどGPUに依存している。もはや、CPUは、十分に早いのだ。現代では、CPUの実行時間を100%必要とする処理は、動画のエンコードぐらいなものであろう。

GPUは、今後もしばらく、性能向上が続く。ただし、GPUの新機能を使ったPCゲームは、次世代コンソールが登場するまで待たねばならない。これは、後述する。

SSDの未来。SSDは、容量を増やす必要がある。まだ、SSDの容量は十分ではない。

ソフトウェアの未来。我々は何としても、Windows XPとIEの害悪から解放されねばならない。Windows XPは、もはや使われるべきではないし、IEはブラウザとは到底認め難い。32bitコードも、いずれ何とかしなければならないが、これは、もう10年ぐらいは、どうにもならないだろう。

PCゲームの未来。ここでいうPCゲームとは、MS Windows上で動くゲームのことだ。PCゲームの未来は、あまり明るくない。

そもそも、PCゲームの人口というのは、もともと、そう多くはないのだ。今では、コンソール向けにゲームを開発するついでに、PC版も提供するといった感じになっている。マルチプラットフォームの何が問題かというと、ゲームの設計自体が、コンソールを前提としたものになってしまうことだ。

特に、現行のPCゲームのUIや操作性は、まったくもって洗練されていない。では、コントローラーを使えばいいかというと、そういうわけでもない。大抵の3Dゲームは、コントローラーを入力装置として遊ぶには、極めて苦痛である。私には、3D FPSゲームをコントローラーでプレイする人間の親指の精度が理解出来ない。

ゲームがコンソールに合わせられるということは、GPUの新機能が宝の持ち腐れになってしまうことをも意味する。たとえば、Geometry ShaderとかTessellationなどといった機能は、いまだにあまり活用されていない。PCゲームの市場の規模を考えると、わざわざPC専用に新機能を実装するほどのコストに見合った利益が得られないからであろう。

総じて、PCゲームの未来は暗い。

2010-12-25

Last Chrismas

毎年、クリスマスになると、大抵の店でかかっている歌がある。あまりにも多用されているので、毎年、なんという歌なのか気になっていた。聞くたびに、調べようとは思うのだが、帰宅する頃には、調べるということ自体を、すっかり忘れてしまうのだ。

今日、たまたま覚えていたため、早速調べた。問題の曲は、Last Chrismasであった。この曲は、大勢の歌手によってカバーされている。

日本の店でよく流れている、つぶやくような聞き取りにくいアレは、誰のカバーなのだろう。

出だしは、いつもほとんど聞き取れずにいるのだが、以下の通り。

Last Christmas I gave you my heart
But the very next day you gave it away
This year to save me from tears
I'll give it to someone special

なんと、失恋の歌だったとは気がつかなかった。

2010-12-24

C++0xによるコンパイル時の配列生成

Don't do this at home. I am professional.
絶対にマネをしてはいけません。

コンパイルタイムプログラミング - 主題のない日記

昨晩、これと同じことがC++で出来るかどうか質問を受けた。5という数字が与えられたときに、0,1,2,2,3,3,3,4,4,4,4,5,5,5,5,5という数列をコンパイル時に生成できるかという問題である。

その時は、プリプロセッサー以外に、どうにもうまい実装方法が思いつかなかった。問題は、再帰を止める方法だ。しかし、今朝、改めて問題を考えると、頑張ればなんとかなるのではないかとも思った。

まず、プリプロセッサーによる実装を考えよう。これは、BOOST.Preprocessorを使えば、簡単に実装できる。簡単というのは、C++のプロにとって簡単という意味である。言うまでもなく、プリプロセッサーは邪道であり、中でもBoost.Preprocessorは禁断の秘術である。D&Eの第18章を暗唱できるようになるまで、プリプロセッサーを書いてはならない。今回は、メタプログラミングの可能性を示すために、あえて、この極悪非道の魔術を使うことにする。

#include <boost/preprocessor/enum.hpp>
#include <boost/preprocessor/enum_shifted.hpp>
#include <boost/preprocessor/arithmetic.hpp>

#define HITO_PRINT_PP( z, n, data ) data

#define HITO_DUP_HELPER_PP( z, n, data ) \
BOOST_PP_ENUM_ ## z( n, HITO_PRINT_PP, n )

#define HITO_DUP_PP( COUNT ) \
0, BOOST_PP_ENUM_SHIFTED( BOOST_PP_ADD(COUNT, 1), HITO_DUP_HELPER_PP, ~ )

int main()
{
    constexpr int a[] = { HITO_DUP_PP(5) } ;

    for( auto value : a )
    { std::cout << value << "," ; }
}

このメタプログラムは、コンマで区切られた目的の数列を生成してくれる。

問題は二つある。まず第一に、これはプリプロセッサーである。第二に、BOOST_PP_LIMIT_REPEATまでしか数列を生成できない。BOOST_PP_LIMIT_REPEATの値は、現在のところ、256である。

では、これを本当のC++0xの言語機能で実装しよう。まず、前提知識として、配列を返す関数を書くことはできない。これは、C++の制限である。そこで、配列をメンバーに持つリテラル型を使うことにする。std::arrayは、ちょうどこの条件をみたしている。

どうやって配列を初期化するのか。それには、Variadic Templatesを用いる。以下のようにpack expansionをしてやればいいのだ。

template < typename ... Types >
std::array< int, sizeof...(Types) > f( Types ... args  )
{
    return std::array< int, sizeof...(Types) >{ args... } ;
}

つまり、この関数をconstexprにして、再帰で実引数を加えていき、目的の数列を生成した上で、std::arrayを返せばいいのだ。問題は、再帰を止める条件である。C++0xでは、関数も特殊化できるようになった。しかし、部分的特殊化はできない。そのため、クラスを使うしかない。

また、std::arrayのサイズは、最初のインスタンス化の際に決定して置かなければならない。つまり、数列の数の個数を、あらかじめ与えてやらなければならない。幸いにして、この非常に難しい数学上の難問は、300年以上前に、当時小学生のガウス君が、宿題を真面目にやるのがめんどくさかったという理由によって、見事に解決してくれている。

// summation from n=0 to i of n
constexpr std::size_t summation( std::size_t i )
{
    return 1 + i * (i + 1) / 2 ;
}

// for compile time selection
template < bool, bool >
struct selector ;

// list construction completed.
template < bool b >
struct selector< true, b >
{
    template < std::size_t COUNT , int I, int J, typename ... Types >
    constexpr static std::array<int, summation( COUNT )> invoke( Types ... args )
    {
        return std::array<int, summation( COUNT )>{ args... } ;
    }
} ;

// add number I, I times.
template < >
struct selector< false, true >
{
    template < std::size_t COUNT , int I, int J, typename ... Types >
    constexpr static std::array< int, summation( COUNT ) > invoke( Types ... args )
    {
        return selector< (COUNT < I), I != J + 1 >:: template invoke< COUNT, I, J + 1 >( args..., I ) ;
    }
} ;

// carry over to the next number.
template < >
struct selector< false, false >
{
    template < std::size_t COUNT , int I, int J, typename ... Types >
    constexpr static std::array< int, summation( COUNT ) > invoke( Types ... args )
    {
        return selector< (COUNT < I + 1), true >:: template invoke< COUNT, I + 1, 0 >( args... ) ;
    }
} ;

// User Interface
template < std::size_t COUNT >
constexpr std::array< int, summation( COUNT ) > dup( void )
{
    return selector< (COUNT < 1), true >:: template invoke< COUNT, 1, 0 >( 0 ) ;
}

int main()
{
    constexpr auto a = dup<5>() ;

    for( auto value : a )
    { std::cout << value << "," ; }
}

selectorクラスを三つに特殊化し、それぞれで別のことをしているのには、理由がある。というのも、単にひとつの関数に条件演算子を使って書いたのでは、インスタンス化を止めることができないからである。つまり、どの処理をするか判定した後まで、インスタンス化を遅らせる必要があるのだ。そのために特殊化が必要になる。

さて、ここで非常に悲しい事実が判明した。このC++0xの機能をあますところなく使った美しいコードは、なんと、最新のgcc 4.6では、dup<18>までしかインスタンス化できないのである。片や、プリプロセッサーはHITO_DUP_PP(256)まで、問題なくコンパイルできるというのに。なんと、プリプロセッサーに負けてしまったのだ。

ちなみに、これは私の経験上、もっとも難しかったテンプレートメタプログラムである。このコードを書くのに二時間半も費やしてしまった。このコードのデバッグは、非常に困難であった。何しろこのコードで、再帰的インスタンス化を止められなければ、gccが一切のエラーメッセージを出さずにクラッシュしてしまうのだから。

追記:MPLを使ったところ、非常に分かりやすくなった。

#include <boost/mpl/if.hpp>
#include <boost/mpl/eval_if.hpp>


// summation from n=0 to i of n
constexpr std::size_t summation( std::size_t i )
{
    return 1 + i * (i + 1) / 2 ;
}

// we've done it. return the result.
struct construct_initializer_list
{
    typedef construct_initializer_list type ;

    template < std::size_t COUNT , int I, int J, typename ... Types >
    constexpr static std::array<int, summation( COUNT )> invoke( Types ... args )
    {
        return std::array<int, summation( COUNT )>{ args... } ;
    }
} ;

struct carry_over ; // forward declaration

// add a initilizaer of number I, I times.
struct add_initializer
{
    template < std::size_t COUNT , int I, int J, typename ... Types >
    constexpr static std::array< int, summation( COUNT ) > invoke( Types ... args )
    {
        return boost::mpl::eval_if_c< ( COUNT < I ),
        /* if true then*/ construct_initializer_list,
        /* else */ boost::mpl::if_c< ( I != J + 1),
            /* if true then*/ add_initializer,
            /* else*/ carry_over > >::type:: template invoke< COUNT, I, J + 1>( args..., I ) ;
    }
} ;

// carry over to the next number
struct carry_over
{
    template < std::size_t COUNT , int I, int J, typename ... Types >
    constexpr static std::array< int, summation( COUNT ) > invoke( Types ... args )
    {
        return boost::mpl::if_c< ( COUNT < I + 1 ),
        /* if true then*/ construct_initializer_list,
        /* else */ add_initializer >::type:: template invoke< COUNT, I + 1, 0 >( args... ) ;
    }
} ;

// User Interface
template < std::size_t COUNT >
constexpr std::array< int, summation( COUNT ) > dup( void )
{
    return boost::mpl::if_c< ( COUNT < 1 ),
    /* if true then*/ construct_initializer_list,
    /* else */ add_initializer >::type:: template invoke< COUNT, 1, 0 >( 0 ) ;
}


int main()
{
    constexpr auto a = dup<5>() ;

    for( auto value : a )
    { std::cout << value << "," ; }
}

2010-12-19

The Elder Scroll V : Skyrimの歌詞

Trailerで使われている音楽の歌詞の書き起こしが、ぼつぼつ出始めている。ただし、なぜか意見が別れている。

ひとつは、以下のような歌詞である。

For the King, For the King
For the fate of Skyrim.
For the Nine, for the Wulf
For the Godless One
And he'll do it for the Just
For the sole single star
For the King, For the King
For the Dawn will rise. Yah!

もうひとつは、以下のような歌詞である。

For the king, For the King
For the sake of Skyrim
For our life, for our Home
For Hrothgars blood
For the Nords, For the gods
For the sole single son
Dovakiin, our king, who'll dawn with fire!

私には、後者の方が正しいように聞こえる。前者は、そのように聞こえないばかりか、意味が通じない部分も多い。

追記:Dovakiinは、おそらくDragon Bornの意味であろう。Hrothgarは、Skyrimにある山の名前であり、Nordの祖先が生まれたとされている場所である。

2010-12-18

The Elder Scroll : Skyrimのpodcast

Bethesda Blog » Blog Archive » The Bethesda Podcast Episode 6: Enter the Dragon

とくにゲーム内容には言及していない。ただし、来年の一月半ばあたりに、結構な量の情報が公開されるらしい。

ちなみに、BethesdaのTwitterのつぶやきによると、新エンジンらしい。Twitter / Nick Breckon: We can now confirm that th ...

ようやく、OblivionとFalloutで使われてきた糞古い環境からおさらばできるのか。こんどはまともな物理演算がなされているといいのだが。

とりあえず、メインテーマでも聞きながら待とう。

GoogleのBooks Ngram Viewerが面白い

Google Labs - Books Ngram Viewer
Official Google Blog: Find out what’s in a word, or five, with the Google Books Ngram Viewer

興味深い。ぜひ日本語版も欲しい。

Chrome Devがアップデートできない場合

現時点でのChromeのDev版のバージョンは、10.0.612.1である。

ところが、どうもエラーがでてアップデート出来ない問題が、広く発生しているようだ。エラーメッセージは、Update server not available (error: 7)である。

これを解決するには、Chromeの再インストールをするしかない。もちろん、引き続きDev版を使いたい場合は、かつてしたように、設定しなければならない。

Google Chrome Releases: Dev Channel Update
"Update server not available" : Installation and update issues (Windows) - Google Chrome Help

2010-12-13

無料の店、強盗にあうこと

CBC News - Edmonton - Thieves target Edmonton free store

エドモントン(訳注:カナダのアルバータ州)にある、ちょっと風変わりな店に、二人組の強盗が押し入ったことで、店長は、首をかしげている。

なぜ押し入る必要があるのか、と店長は言う。店にあるものはすべて、無料なのに。

84番街と118番通りの近くにある、このフリーストアは、今年、開いたばかりである。ここでは、2ドルを支払うことで、店に不要な物を引きとってもらうことができる。お客は、店にあるものを何でも、無料で手に入れることができる。

店の共同経営者であるBrandon Tysonは、木曜日の夜に店に来たところ、二人組の男が店内にいるのに気がついた。彼らは窓ガラスを蹴破り、店内にはガラス片が散乱していたのである。

「無料の店として、我々は誰かが強盗に押し入るなどということを想定していませんでした。というのも、次の日にやってきて、全部無料で持って帰ればいいのですから」とTysonは言う。「まあ、それでも、強盗というものは、いるんですね」

Tysonは二人組の強盗未遂を店の外まで追いかけ、捕まえた上で、警察を呼んだ。二人組は酒に酔っていたという。

Tysonは、この事件は実に奇妙だと言う。

「ここは無料の店なのです」と彼は言う。「ここにあるものは全部無料で持って帰ることができます。そうすることによって、これらの資源は、ゴミの埋立から免れるわけです」

「そういうわけで、ここに実際に誰かが押し入って、物を盗んでいくというのは、実におかしいのです。いいジョークのネタになりますな」

彼らが処罰されたかどうかは不明である。

おいしいチャーハンの作り方

今日は、奇跡的に素晴らしいパラパラのチャーハンが作れた。作り方を、忘れないように書いておこうと思う。

  • 米は炊き上げて、一日ほど放置したものを用いること
  • 具は出来る限り細かく切り刻むこと
  • 具と米は別々に炒めること
  • 卵をフライパンに投下した後、ただちに米も投下して、かき混ぜつつ炒めると、米がパラパラになってよし

2010-12-12

TES 5: Skyrimのサイトが結構すごい件

The Elder Scrolls V: Skyrim

まともなHTML5マークアップを使っている。たしかに、HTML5 Validatorsに通すと、いくつかのエラーを吐くが、どれも実質は問題のないエラーばかりである。

私は、Flashを無効にしているが、ちゃんとvideo要素を使っているために、動画が表示される。素晴らしい。

あとは、TES 5: Skyrimが、Unicodeを使っていればいいのだが。

これはひどい

経済産業省 会見・スピーチ 大臣記者会見

ソースを見てほしい。このような邪悪なHTMLがいまどき存在を許されるのだろうか。

なんという前衛芸術のようなdivだろうか。

さらに細かいことをいうと、HTML4.01としてもおかしい。

まず、HTMLだが、DOCTYPE指定がない。つまりこのサイトは、互換モードで表示されているということになる。

次に、目につくのは、body > center > tableである。いまどき、レイアウトをテーブルで組んでいるのだ。ああ虫酸が走る。もちろん、邪悪なfont要素も使っている。吐き気をもよおす邪悪とは、このようなことをいうのだろう。centerとfontは、HTML4.01ですら廃止予定の要素である。ここまでくれば、もう誰も驚かないだろう。width、 height、bgcolor、alignなどという属性は、当然のごとく使っている。まあ、些細な問題だろう。

また、文字コードは当然のごとくShift JISである。日本人であるからこそ、一刻も早くShift JISを捨て去らなければならないというのに。

ああ、日本の将来は暗い。

追記:今頃気がついたのだが、DOCTYPEすらない。すると、これは互換モードで解釈されるのであって、このような邪悪なHTMLでも問題はないということになる・・・いや、それをやっちゃ駄目だろう。

これもひどい。

中学生のコンピュータの問題 | Okumura's Blog

  • 文字,数字,図形,静止画像,動画像,音声などを(情報)という。
  • 漢字変換は,(日本語変換)システムで行っている。
  • インターネットに接続するには,プロバイダと契約し,メールアドレス以外に何を取得する必要があるか。( パスワード

分からん。

これは良いニュース

金沢市長選:当選陣営がツイッターで選挙戦 指導を無視し - 毎日jp(毎日新聞)

たぶん、ネット利用が公職選挙法違反に当たるかどうかは、前例がないから誰も分からないんだろう。そんな法律に縛られて今まで選挙期間中はインターネット禁止などという時代錯誤のドブ板選挙をしていたのでは、日本の将来のために害悪である。

本来ならば、とっくの昔に公職選挙法は改正されているべきであるが、いまだに変わっていない。これは、現行の政治家が、特に変える必要はないと考えているためであろう。日本の将来のために害悪である。

The Elder Scroll V: Skyrimが発表された

もう、かれこれ一二年ぐらいは噂になっていたが、どうとうTrailerがでた。

動画によると、2011年11月11日に発売されるらしい。

かねてからの噂通り、時代はOblivionゲートが開いた後の世である。場所はCyrodiilの北に位置するSkyrim(Nordの故郷)である。かなりの寒冷地であると予想される。一面雪景色なのだろうか。ちなみに、Skyrimがゲームの舞台になるのは、実に第一作のArena以来である。動画では、Dragon Bornと言っている。つまり、Septimと同じく、新たなドラゴンの血を引く皇帝が誕生するということだろうか。

You should have acted.
They're already here.
The Elder Scrolls told of their return.
Their defeat was merely delay.
Til the time after Oblivion opened.
When the sons of Skyrim would spill their own blood.
But no-one wanted to believe.
Believe they even existed.
And when the truth finally dawns:
It dawns in fire.
But...
There's one they fear.
In their tongue, he's Novak'leen Dragon Born!

ちなみに、歴史を振り返ってみると、これまでのTESは、すべて、Dragon BornであるEmperor Uriel Septim VIIの御宇の話であった。最後の血筋であるMartin Septimが薨去したことにより(戴冠したかどうか微妙なので、崩御は正しくないだろう)、TES5の世界では、Dragon Bornがいないということになる。

ちなみに、Oblivionより後日談を書いた小説によれば、TES4: Oblivion以降のFourth Eraでは、Tamrielの統一が崩れ、Black Marsh(Aragonianの故郷)とElsweyr(Khajiitの故郷)が独立した。MorrowindはAragonianによって征服された。

Lore:Fourth Era - UESPWiki

2010-12-10

ペンタゴンがリムーバブルメディアを禁止するらしい

Military Bans Disks, Threatens Courts-Martial to Stop New Leaks | Danger Room | Wired.com

しかし問題は、対象となるコンピューターはたいてい、ネットワークにつながっていないか、つながっていたとしても、相当遅い。そのため、外部メディアでデータを持ってくるのだが、それができなくなった。曰く、「家を建てろと言っておきながら、ハンマーを禁止するようなものだ」

そもそも、そのようなコンピューターのソフトウェアを、どうやって更新するつもりなのだろうか。厳重に管理されるべきコンピューターが、既知の脆弱性に対するパッチを適用していない状態になるのだろうか。それでは、リークしてくれと言っているようなものではないか。

2010-12-07

ソーシャルネットワーキングの過去、現在、未来

Social Networking: The Past
Social Networking: The Present
Social Networking: The Future

これは興味深い。気になる意見をまとめてみた。

まず過去。ソーシャルネットワーキングというものは、何も今に始まったものではないということ。大昔から似たようなサービスはあった。

面白いのは、かつて市場をほぼ独占したサービスなのに、今はすっかり衰えているものがあるということだ。例えばAOLだ。AOLは、他社を参入させず、独自のネットワークをつくろうとした。そこでは、AOLが管理し、AOLが善悪を決めるのだ。かつて、AOLはインターネットにも参入した。かつて、AOLが史上を独占してしまうのではないかと恐れられた。今から考えると、笑い話である。そのような独裁は、成功しなかった。WWWがやってきて、HTMLでWebサイトが記述できるようになると、AOLの独裁は終わった。

WWWではYahooが突出した。Yahooの勢いは、誰に求められないように思われた。今から考えれば、笑い話である。

さて、現在。現在主流のソーシャルネットワーキングサービスを、スパムベースであるとしている。つまり、自分が何をしているかという情報を、友人全員に送りつけるのである。

ブログが登場した。しかし、ブログはあまり残らなかった。というのも、大衆は、ブログを書きたいとは思わなかったからだ。大衆は画像や動画をアップロードして、それについて議論したかったのである。皆が皆、長々とブログを書くわけではない。

そこに、Myspaceが登場した。アイディアはよかったものの、Myspaceは、画像や動画をうまく扱えなかった。そこでユーザーは、、画像や動画を、専用のサイトにアップロードし、Myspaceからは、単にリンクを貼るという使い方をした。

FoxがMyspaceを買収した。FoxのRupert Murdochは、頭が良さそうに見えた。実際はそうでもなかった。Myspaceは、Facebookに負けたのだ。

なぜMyspaceはFacebookに負けたのか。それは、他社を締めだしたからである。一方、FacebookはAPIを提供して、開発を推奨した。シリコンバレー30年のビジネス上の歴史を振り返るに、「オープンにして、あとで課税しろ」というのが、成功する秘訣のように思われる。

Foxはまた明らかに成功しなさそうなことを始めた。御年75歳のRupert Murdochには、イノベーションというものが分かっていないらしい。22歳のMark Zuckerbergに勝てるわけがない。

最後に、ソーシャルネットワーキングは、リアルタイムになった。Twitterである。

未来はどうなるのか。まず、Facebookの独占などということはありえない。かつてはMicrosoftが、Yahooが、Googleが、それぞれ市場を独占してしまうのではないかと恐れられた。もちろん、今となっては笑い話でしかない。

ソーシャルネットワーキングは、オープンになるべきだと言っている。どこか一社にロックインされるのは、誰も望んでいないし、ロックインしようとしても無駄だろうと。

Facebook connectとかいって、サイトにFacebook上の情報を得る許可を出すボタンがあるが、あの情報の使い方も、もう少し研究する必要がある。今は、単にユーザーの嗜好に合わせた広告を出すぐらいにしか使われていない。他の使い方もあるはずだ。

プライバシーの問題も少しだけ触れている。しかし、それほど問題にはならないだろうと言っている。

また、プライベートとビジネスを分けるべきだとも言っている。自分の妻子の写真だとか、学生時代のマヌケな写真だとかを、ビジネス上の相手と共有してもしょうがない。今、Facebookは、プライベートとビジネスを分けていない。そこで、アカウントを複数使い分けているユーザーが結構いる。これを分けるべきだ。

2010-12-04

日本ではプログラミングすべきではない

librahack事件はちっとも終わってない。岡崎市立図書館は被害届を取り下げるべき。MDISはそれにとことんつきあうべき。

無実の罪で逮捕、拘留されるからである。

post-Batavia mailiingの簡易レビュー

ISO/IEC JTC1/SC22/WG21 - Papers 2010

最新ドラフトは、N3225になった。ドラフトに対する変更点は、N3226: Editor’s Reportに列挙されている。

今回は、名前通りの単純な変更や、単なる文面の誤りや不明確な点の修正などが多い。そのため、特に気になるペーパーだけを取り上げる。

N3189: Observers for the three handler functions

get_new_handler, get_unexpected, get_terminateを追加する提案。

N3197: Lockable Requirements for C++0x

名前通り。

N3198: Deprecating unary/binary_function (Rev 1)

これまた名前通り。当然deprecatedにするべきである。

N3201: Moving right along

重いコンダラ試練の道を~♪ 行くには行くが、下位互換性は守るのが標準化委員会のド根性。

暗黙のムーブを、どのような場合に生成すべきか。また、暗黙のムーブはどのように実装されるべきかという問題について論じている。

暗黙のムーブは、ユーザー定義のコピーやムーブ、デストラクターに加えて、コンストラクターが存在する場合も、生成を抑制されるべきではないかという話がひとつ。

もうひとつ、暗黙のムーブの実装をどのように定義すればよいか。問題となるのは、ムーブした後のオブジェクトのことだ。ライブラリ実装者としては、ムーブされた後のオブジェクトは、代入などをすれば使える状態であってほしい。

Object x ;
Object y = std::move( x ) ;
// xはムーブされた後の状態になる
Object z ;
x = z ; // xが使用可能の状態になる。

しかし、一体この状態をどうやって作り出せばいいのか。クラスの実装次第では、ムーブ後のオブジェクトに対する代入ができない可能性もある。では、ムーブ後の状態を、暗黙のムーブという一般的な実装から作り出すのは、どうすればいいのか。

デフォルトコンストラクターを使うというのはどうだろう。つまり、暗黙のムーブは、各メンバーごとにムーブした後のオブジェクトに対して、デフォルトコンストラクターを呼び出すのだ。これによって、妥当な状態にすることができる。もし、別の実装がしたければ、ユーザーは自前のムーブを実装すべきである。

しかし、勝手にデフォルトコンストラクターが呼び出されるというのは、やはり色々と問題がある。さて、どうするか。

個人的には、現行FCDのままの方が、一番混乱が少なくていいと思う。

N3202: To which extent can noexcept be deduced?

noexceptには、ひとつ問題がある。わざわざ、すべての関数にnoexceptを指定するのが、甚だ面倒だということだ。それゆえ、インライン関数は、noexceptを暗黙のうちに推定してもいいのではないだろうか。つまり、インライン関数の関数本体に、例外を投げるかもしれない式が含まれていない場合、そのインライン関数は、noexcept(true)と暗黙のうちに指定されるべきではないか。という提案。

N3203: Tightening the conditions for generating implicit moves

ユーザー定義のコピー、ムーブ、デストラクターがある場合、暗黙のムーブを生成しない。ユーザー定義のコピー、ムーブ、デストラクターがある場合、暗黙のコピーを生成する機能を、deprecatedにする。

ユーザー定義のコピーがあるのに暗黙のコピーを生成する場合というのは、すこし妙に聞こえるかもしれない。これは、ユーザー定義のコピー代入演算子があって、コピーコンストラクターが定義されていない場合、またはその逆である。

struct X
{
    // ユーザー定義のコピー代入演算子
    X & operator = ( X const & ) { return *this ; }

    // 暗黙のコピーコンストラクターが生成される
} ;

このような挙動は、C++0xではdeprecatedであるので、まともなC++プログラマーならば、この挙動に頼ったコードを書いてはいけない。

N3204: Deducing "noexcept" for destructors

デストラクターに明示的にnoexceptが指定されていない場合、暗黙のデストラクターと同じ方法でnoexceptが推定される。結果的に、明示的にnoexcept(false)を指定しない限り、デストラクターはnoexcept(true)となる。

n3205 Delete operators default to noexcept

名前通り。

N3206: Override control: Eliminating Attributes

いままでattributeの機能であった、base_check, final, override, hidingを、contextual keywordにする。base_checkはexplicitに、hidingはnewになる。

struct Base
{
    int x ;
    virtual void f() ;
} ;

struct Derived explicit final : Base
{
    int x new ;
    void f() override ;
} ;

finalとoverrideは、contextual keywordなので、識別子としても利用出来る。

ただし、会議後、この文法にも新たな問題が見つかっており、おそらく、また文法は変わるだろうと思われる。ひょっとすると、hidingがなくなってしまうかもしれない。

N3207: noexcept(auto)

関数の本体から、noexceptを推定させるための例外指定を追加する提案。以下のようになる。

void f() {} // 例外を投げるかもしれない関数
void g() noexcept { } // 例外を投げないと保証されている関数

// noexcept(false)
void h() noexcept(auto)
{
    f() ; // 例外を投げる可能性のある式
}

// noexcept(true)
void i() noexcept(auto)
{
    g() ; // 例外を投げる可能性のない式
} 

N3209: Progress guarantees for C++0x (revised)

残念ながら、私はこのペーパーの内容を理解していない。スレッド間の保証は難しい。

N3210: New wording for arithmetic on ratios

文面の書き換え

N3214: US 19: Ambiguous use of "use" (version 2)

ODRのuseと、一般動詞としてのuseが混用されていてややこしいというNBコメントに対し、ODRに関するuseを、odr-useに置き換える変更。

N3216: Removing Implicit Move Constructors and Move Assignment Operators

今回のドラフトでは採用されなかったが、もし、暗黙のムーブを取り除くとした場合の、規格の文面の変更案。

N3217: Wording for brace-initializers as default arguments

{}をデフォルト実引数として使えるようにするための文面。

N3218: Core Issue 1125: Unclear definition of "potential constant expression" (DE 8, GB 26)

定数式の文面の不明確な点を解消。

std::size_tの定義のたらい回し

ちょっと面白かったので紹介する。

C++ Standard Core Language Defect Reports: issue 1122

The return type of the sizeof operator is defined as being of type std::size_t, defined in library clause 18.2 [support.types]. This, in turn, says that size_t is defined in the C standard, which in turn says that size_t is defined as the type of the result of the sizeof operator!

sizeof演算子の戻り値の型は、std::size_t型であるとされている。std::size_tは、ライブラリ18.2[support.types]で定義されている。そこでは、size_tはC規格で定義されているとしている。C規格では、size_tはsizeof演算子の結果の型であると定義されている!

なんというたらい回し。

必死で修正

現在、Batavia会議での変更に対応するべく、必死で既存の文章を修正している。いつもやっている簡易レビューは、少し遅れるかもしれない。

2010-12-02

YoutubeをHTML5で埋め込むタグを生成するbookmarklet

以下は、Youtubeの動画をHTML5のvideo要素を使って埋め込むためのコードを生成するbookmarkletである。これは、http://www.youtube.com/watch?v=で始まるURL上で使うことを想定している。マイチャンネル上で使うことは想定していない。

javascript:(function(){ var url = document.URL ; var id = url.slice( url.search("v=") + 2 ) ; id = id.slice(0, id.search(/(&)|($)/) ) ; var str = '<div><iframe class="youtube-player" type="text/html" width="640" height="505" src="http://www.youtube.com/embed/' + id + '" frameborder="0"></iframe><br /><a href="http://www.youtube.com/watch?v=' + id + '">' + document.title + '</a></div>' ; prompt("", str ) ; })() ;

これは、まだ実験段階のYoutubeの埋め込みコードを使っている。詳しくは、YouTube API Blog: A New Way To Embed YouTube Videosを参照。また、YouTubeにHTML5のvideo要素を使わせるためには、この設定ページで、HTML5を有効にしなければならない。

Webの正しい進化のためには、Flashを撲滅すべきである。当然だ。しかし、私はいまだにFlash Playerを有効にしている。これはよろしくない。たしかに、Flashというコンテンツをみるためには、Flash Playerが必要だ。しかし、真に見る価値のあるFlashというのは、実はそれほど多くない。ゆえに、通常はFlash Playerは無効にすべきであるという結論に至った。

さて、現在のWebで、どうしてもFlashが必要なコンテンツとはなにか。動画である。数ある動画サイトでも、最も有名なサービスはYouTubeである。YouTubeには、話題の動画が数多く上げられている。単なる娯楽であれば、見ないという選択もできるが、そうはいかない。最新の技術や製品の説明が、動画を使って行われていることも、しばしばある。

そもそも、最新の研究結果によれば、インターネットはぬこによって構成されているのである。

しかし、既存の埋め込みのYoutube動画は、いずれもflashを直接参照している。これでは動画を見ることができない。HTML5で埋め込む方法は、実験段階とはいえ、公式に公開されている。そこで、このBookmarkletをつくることにした。

YouTubeを埋め込む者は、せめて、YouTubeの該当URLへの、直接のリンクを貼るべきである。Flash Playerを使っていない人間は、たとえ動画がWebMでエンコードされていて、ブラウザがHTML5のvideo要素でWebM再生をサポートしていたとしても、YouTubeを再生できなくなってしまう。また、リンクがないので、ソースを読まない限り、該当ページに飛ぶこともできない。また、その際、マイチャンネルにリンクをはってはいけない。なぜならば、マイチャンネル上では、Flashが強制されてしまうからだ。

追記:2011/01/26、バグ修正。

イスラエルをボイコットするとPCは使用不可

良品計画がイスラエルへの出店を取りやめるらしい。もし、馬鹿げたボイコットに影響されたのだとしたら、それこそ馬鹿げた事だ。

そもそも、本当にイスラエルをボイコットしたら、PCは使えない。

イスラエルをボイコットしたい君、もしかして、手持ちのPCは、Intel製のCPUを使っているのではないだろうか。もしそうならば、今すぐにたたき壊すべきだ。IntelのCPUはイスラエル人が開発している。

イスラエルをボイコットしたい君、もしかして、手持ちのPCは、AMD製のCPUを使っているのではないだろうか。もしそうならば、今すぐにたたき壊すべきだ。AMDのCPUはイスラエル人が開発している。

彼らは商人である。国ではない。商人は国に対してどうしようもできないのだ。国は国でなければ相手ができない。もしイスラエルを変えたいのならば、真にすべきことは、自国の政府をして公式にイスラエルを批難させることである。商人にものをいっても、国は変わらない。

まあ、イスラエルはどうしようもない国であることは確かだ。第一、奴ら人種的にユダヤ人というわけでもないだろうに、理解出来ないことだ。

2010-12-01

寿命と所得の視覚化

この視覚化はすごい。

追記:はてブで、「横軸が対数だから実はアフリカはぶっちぎりで取り残されてるのでは」という意見があるようだ。

追記2:ついでにいうと、基軸通貨の価値も、当時とは変わっているのではないかと思う。

私選弁護士を雇えない限り日本でプログラミングしてはならない

Librahackメモ | Librahack : 容疑者から見た岡崎図書館事件

私選弁護士を雇えない限り日本でプログラミングしてはならない。いや、それをするぐらいなら、海外で開発すべきだ。悲しいことだ。

mixiが派手に失敗している件

もう、SNS需要は一巡している。つまり、SNSに興味を示すユーザーは、すでにどこかのSNSサービスを使っているであろう。つまり、SNSは、もうこれ以上ユーザー数を増やすことはできないのだ。

これはSNSにとって問題である。従来、SNSの収入は広告に頼っていた。今では、SNS内のゲームによる収入もかなりあるが、やはり、まだ広告の力は大きい。手っ取り早く広告収入を上げるためには、ユーザー数は多ければ多いほどいい。また、新規ユーザーを常に獲得しなければならない。というのも、新規に入ってきたユーザーは、すでにいる興味が覚めたユーザーより、より多く操作をするので、広告収入もより得られるであろう。

広告収入を上げるには、Webサイトで操作している時間を増やすのが、非常に効果的である。

しかし、SNS需要はすでに一巡している。得られないものを得るためには、新規の何かが必要である。従来、ほとんどのSNSというのは、招待制であった。つまり、一見さんお断り、既存ユーザーから招待されない限り参加できないというものであった。これは、ユーザーの急激な増加を防ぐというよりは、単に話題取りのための仕様であった。SNS需要が一巡した今、そのような宣伝は取り除かれなければならない。

今回、mixiは、アカウントに紐付けられている、メールアドレスによる検索を可能にした。これは、一時的な広告収入を得る手段として、素晴らしいといえる。私は正気である。広告収入を上げる手段として、素晴らしいのだ。

なぜ素晴らしいのか。というのも、従来、アカウント用のメールアドレスは公開されていなかった。そのため、ユーザーは、そのことを前提にした活動をしていた。これを急に変更するとどうなるのか。メールアドレスに対して、素晴らしい個人情報が得られるのだ。あらゆる利用が考えられる。検索しない手はない。すなわち、操作が増える。操作が増えると、広告収入が上がる。

もちろん、これはユーザー側からすれば、個人情報の切り売りである。とんでもないことである。だから、私のようなパワーユーザー(笑)は、この手のサービスに対して、実際に使っているメアドとは別の、捨てアドを設定しておくのだ。しかし、捨てアドとはいえ、複数のサイトで使い回しているアドレスである。これが公開され、紐付けられてしまうのは、やはり困る。

まあ、私などは、mixiは単に登録しているだけである。日記は、このブログのRSSを流し込んでいるだけだ。しかし、そろそろ手を切るべき時期だろう。足あとによると、私のmixiアカウントを定期的に見ているのは、三人ぐらい。このブログ記事が、mixi日記に流し込まれて、登録してある友人が見るまでの数日、アカウントを保持して、それから消すことにしよう。

ニコニコ動画に引き続き、mixiも終わったか。日本のインターネット史を編纂する際には、必ず言及されるであろうサービスだ。栄枯衰勢というか、諸行無常というか。

次に消えるサービスはなにか。オンラインブックマークは、すでに下火である。はてなブックマークも、Diggも、かつての勢いはない。Micro bloggingは、死ぬべきである。ただ、これは、ブログに長文を書けない者、リテラシーのない者への、文盲用サービスとして、しばらく生き残るだろう。

私がまだしばらく使うであろうと思われるWebサービスは、メールとフィードリーダーである。私の場合、GMailとGoogle Readerを使っている。

まだ、Eメールに置き換わるプロトコルは発明されていない。たとえばこのmixiの問題にしたって、いまだにメールが重要だからこそ、問題なのだ。これが、単にログインIDで検索できる程度なら、それほど問題にはならないだろう。ログインIDは、それほど重要ではないからである。

Webの多くの更新情報は、単純なテキストで表現できるので、フィードは便利である。わざわざWebサイトを巡回しなくてもよい。そう、まだフィードリーダーが一般的ではなかった頃、かつては巡回と称し、お気に入りのサイトの更新を、手動で確認する原始的な更新チェックが行われていたのだ。いまだに少し力を持っている、ニュースサイト(フィードすら提供していない日々更新されるリンク集)なるものも、あの時代の名残であると言える。

メールとフィードは、いつ廃れるだろうか。その時、一体我々は何を替わりに使っているのであろうか。

Splashtop OS

Splashtop OS beta

  1. Windowsからインストールする
  2. 設定変更もWindows上から行う
  3. 電源投入から数秒で起動可能
  4. ChromiumブラウザとFlashが使える
  5. 無料である

Chrome OSの対抗馬を意識したOS。設定変更すら、ほとんどをWindows上から行う。このOSでは、ブラウザぐらいしか使うことはできない。その代わりに、数秒で起動。

ところで、このことは日経新聞で知ったのだが、その日本語が不思議すぎて笑える。

マイクロソフト、高速起動OS無料配布 :日本経済新聞

高速で起動できるOS(基本ソフト)の無料ダウンロード(取り込み)を始めたと発表した。

基本ソフト、取り込み・・・んん? 余計に分からなくなっている。しかも最悪なことは、当のSplashtop OSのウェブサイトへのリンクが貼られていない。上記のサイトは、ググッて見つける必要があった。そりゃ、基本ソフトとか取り込みとかいう、不思議な言葉を使うわけだ。事によると、連中はまだ、社内では漢語を使っているのではあるまいか。

2010-11-30

C++のINVOKEの仕様

std::funcitonやstd::bindは、20.8.2 Requirements [func.require]で定義されているINVOKEの仕様に従う。つまり、メンバー関数やデータメンバーも扱える。

struct Foo
{
    void f() { }
    int x ;
} ;

int main()
{
    Foo foo ;
    // メンバー関数
    std::function< void ( Foo & ) > f( &Foo::f ) ;
    f( foo ) ; // foo.f() と同じ

    // データメンバー
    std::function< int & ( Foo & ) > x( &Foo::x ) ;
    x( foo ) = 0 ; // foo.x = 0 と同じ
}

もしかして、意外と知られていないのだろうか。

hidingに黄信号

ひょっとしたら削除されるかもしれない。それはそれで、教える手間が省けて、こちらとしても都合がいいのだが。

hidingを正しく教育するのは、至難の業である。

しかし、やはりoverrideはあるのにhidingがないというのは、片手落ちの感がある。

常用漢字表

常用漢字表

まあ、いろいろ紆余曲折があったようだが、(どっかのアホが俺とか糞などという漢字は野蛮であるから含めるべきではないとも主張したと聞いているが)、だいぶマシになったのではないかと思う。

とめ、はね、はらいなどの、表記の些細な違いは、区別する必要がないと明記してあるのもよい。本来、それは些細な違いなのだ。小学校などでは、いまだに教科書体にそって正しいとめはねはらいを書かなければならないなどと教育しているのだろうか。嘆かわしいことだ。

アメリカは5度、核爆しかかった

5 times we almost nuked ourselves by accident
アメリカは5度被曝しかけた : ギズモード・ジャパン

被曝は違うような気がするんだけどなぁ。

陰謀論的なことを言えば、まだ明らかにされていない事故がたくさんありそうな気もするけれど。

2010-11-29

std::functionのtargetの使い方

こういうことができる。

void f() { std::cout << "f" << std::endl ; }
void g() { std::cout << "g" << std::endl ; }

int main()
{
    std::function< void ( void ) > func( &f ) ;
    func() ; // f

    *func.target< void (*)(void) >() = &g ;
    func() ; // g
}

誰が使うんだろう。

追記:これだけだと、誤解を招きそうなので、以下のコードを補足しておく。

void f() { std::cout << "f" << std::endl ; }
void g() { std::cout << "g" << std::endl ; }
struct h { void operator ()(void){} ; } ;

int main()
{
    std::function< void ( void ) > func( &f ) ;
    func() ; // f

    *func.target< void (*)(void) >() = &g ;
    func() ; // g

    func = h() ;
    // 実行時エラー、型が合わない
    *func.target< void (*)(void) >() = &g ;
}

一応、std::function経由で呼び出すには、格納されている型を実行時に判断しなければならない。そのため、すでに格納されている型が分かっているのならば、中身を取り出すことで、そのような実行時チェックを、中身を取り出す際の一回で済ませることができる。これは、変更をしないと保証できるstd::functionのオブイェクトに対し、何百万回もoperator ()を呼び出す際に、有効であろう。そんなケースはあまりないと思うが。

void f( std::function < int (int) > f )
{
    // 1000000回の実行時チェックが必要
    for ( int i = 0 ; i != 1000000 ; ++i )
    {
        f(i) ;
    }
}

void g( std::function < int (int) > f )
{
    // fには関数ポインターが入っていると分かっている
    auto func = *f.target< int (*)(int) >() ;
    // 実行時チェックはいらない
    for ( int i = 0 ; i != 1000000 ; ++i )
    {
        func(i) ;
    }
}

もちろん、関数gを以下のように呼び出した場合、実行時エラーになる。

struct Foo { int operator ()(int) const { return 0 ; } } ;

int main()
{
    f( Foo() ) ; // OK
    g( Foo() )  ; // エラー
}

targetは危険である。規格を読んでstd::functionを実装した者でない限り、targetを使ってはいけない。つまり、私は使う資格がある。使いたいとは思わないが。

なぜならば、gは仮引数fの中身の型が、関数ポインターであることを前提にしているからである。

もっともつまらない日は1954年の4月11日

Computer identifies the most boring day in history - Telegraph
Cambridge Computer IDs World's Most Boring Day - Slashdot
「歴史的出来事が最も少なかった日」は1954年4月11日 - スラッシュドット・ジャパン

ケンブリッジ大学の学者によれば、史上最もつまらなかった日は、1954年の4月11日である。

この日は、世界的に特筆すべき出来事もおきていないし、有名人も一人しか生まれていないとのこと。

std::functionの真に正しい実装

だいぶ前の記事では、target()の意味を勘違いしていた。void *へのキャストが出てくるので、おかしいと思ったのだ。しかし、std::functionのtargetって誰が使うんだ、これ。


namespace hito {

class bad_function_call : public std::exception
{
public:
    bad_function_call() {}
    virtual char const * what() const throw()
    {
        return "bad function call exception" ;
    }
} ;

template < typename > class function ;// primary template.

template < typename R, typename ... ArgTypes >
class function< R ( ArgTypes... ) >
{
public :
    typedef R result_type ;

private :

    struct holder_base
    {
        virtual ~holder_base() {}
        virtual holder_base * clone() const = 0 ;
        virtual std::type_info const & target_type() const = 0 ;

        virtual result_type invoke( ArgTypes... ) = 0 ;
    } ;

    template < typename F >
    struct holder : public holder_base
    {
    public :
        holder(F f) : f( f )
        { }
        virtual ~holder() { }

        virtual holder_base * clone() const
        {
            return allocate_holder( f ) ;
        }

        virtual std::type_info const & target_type() const
        {
            return typeid( F ) ;
        }

        virtual result_type invoke( ArgTypes... args )
        {
            return f( std::forward<ArgTypes>(args)... ) ;
        }

        F f ;
    } ;

    template < typename holder_R, typename T, typename ... Types >
    struct member_holder : public holder_base
    {
    public :
        member_holder( holder_R (T::* const f)( Types... ) )
            : f(f)
        { }
        virtual ~member_holder() {}

        virtual holder_base * clone() const
        {
            return allocate_holder( f ) ;
        }

        virtual std::type_info const & target_type() const
        {
            return typeid( f ) ;
        }

        result_type invoke_impl( T t1, Types... args )
        {
            return (t1.*f)( std::forward<Types>(args)... ) ;
        }

        result_type invoke_impl( T * t1, Types... args )
        {
            return ((*t1).*f)( std::forward<Types>(args)... ) ;
        }

        virtual result_type invoke( ArgTypes ... args )
        {
            return invoke_impl( std::forward<ArgTypes>(args)... ) ;
        }

        holder_R (T::* f)( Types...) ;
    } ;

    template < typename T, typename DATA >
    struct data_member_holder : holder_base
    {
    public :
        data_member_holder( DATA T::* const f )
            : f( f )
        { }

        virtual ~data_member_holder() { }

        virtual holder_base * clone() const
        {
            return allocate_holder( f ) ;
        }

        virtual std::type_info const & target_type() const
        {
            return typeid( f ) ;
        }

        result_type invoke_impl( T & t1 )
        {
            return t1.*f ;
        }

        result_type invoke_impl( T * const t1 )
        {
            return (*t1).*f ;
        }

        virtual result_type invoke( ArgTypes ... args )
        {
            return invoke_impl( args... ) ;
        }

        DATA T::* f ;
    } ;

    holder_base * ptr ;

private :

    template < typename F >
    struct make_holder_type
    {
        typedef holder < F > type ;
    } ;
    template < typename holder_R, typename T, typename ... Types >
    struct make_holder_type< holder_R (T::*)( Types... ) >
    {
        typedef member_holder<holder_R, T, Types...> type ;
    } ;

    template < typename T, typename DATA >
    struct make_holder_type< DATA T::* >
    {
        typedef data_member_holder<T, DATA> type ;
    } ;

    template < typename F >
    static holder_base * allocate_holder(F f)
    {
        typedef typename make_holder_type<F>::type type ;
        return new type( f ) ;
    }

    void deallocate_holder()
    {
        delete ptr ;
        ptr = nullptr ;
    }

    holder_base * clone() const
    {
        if ( ptr != nullptr )
            return ptr->clone() ;
        else
            return nullptr ;
    }
    
public :

    explicit function() : ptr( nullptr )  { }
    function( std::nullptr_t ) : ptr( nullptr ) { }

    function( function const & init_expr ) 
        : ptr( init_expr.clone() )
    { }

    function( function && init_expr )
        : ptr( init_expr.ptr )
    {
        init_expr.ptr = nullptr ;
    }

    template < typename F >
    function( F f )
        : ptr( allocate_holder( f ) )
    { }


    function & operator = ( function const & assign_expr )
    {
        if ( this == &assign_expr )
            return *this ;

        deallocate_holder() ;
        this->ptr = assign_expr.clone() ;

        return *this ;
    }

    function & operator = ( function && assign_expr )
    {
        if ( this == &assign_expr )
            return *this ;

        deallocate_holder() ;
        this->ptr = assign_expr.ptr ;
        assign_expr.ptr = nullptr ;

        return *this ;
    }

    function & operator = ( std::nullptr_t )
    {
        deallocate_holder() ;
        return *this ;
    }

    template < typename F >
    function & operator = ( F f )
    {
        delete ptr ;
        ptr = allocate_holder( f ) ;
    }

    ~function()
    {
        deallocate_holder() ;
    }

    void swap( function & arg )
    {
        std::swap( this->ptr, arg.ptr ) ;
    }
    
    explicit operator bool() const
    {
        return bool( ptr != nullptr ) ;
    }

    result_type operator () ( ArgTypes... args ) const
    {
        if ( ptr != nullptr)
            return ptr->invoke( std::forward<ArgTypes>(args)... ) ;
        else
            throw bad_function_call() ;
    }


    std::type_info const & target_type() const
    {
        if ( ptr != nullptr )
            return ptr->target_type() ;
        else
            return typeid( void ) ;
    }

    template < typename T >
    T * target()
    {
        if ( target_type() != typeid(T) )
            return nullptr ;

        typedef typename make_holder_type<T>::type type ;
        auto actual_ptr = static_cast< type * >( ptr ) ;
        return &actual_ptr->f ;
        
    }

    template < typename T >
    T const * target() const
    {
        if ( target_type() != typeid(T) )
            return nullptr ;

        typedef typename make_holder_type<T>::type type ;
        auto actual_ptr = static_cast< type * >( ptr ) ;
        return &actual_ptr->f ;
    }

} ;

}

2010-11-28

多重継承はC++の用語として不適切

C++の規格上、派生と継承は、明確に区別するべきであることはすでに述べた。

本の虫: abstract classで知らなかったこと、付記、派生と継承の違い

ところで、「多重継承」という言葉がある。これは、Multiple Inheritance(複数の継承)という言葉の一般的な訳語である。多重継承は、実はC++には相応しくない言葉である。クラスは派生(derive)するものであって、継承(inherit)するものではないからである。

規格ではどうなっているかというと、Multiple base classes(複数の基本クラス)となっている。規格の文章は多重継承という言葉を使っていない。ただし、注記として、「複数の基本クラスを使うことは、しばしば多重継承と呼ばれている」などと書いてある。つまり、通称として多重継承という言葉が一般的であるということに言及しているのだ。

また、すでに書いている参考書の文章を見なおしたところ、なんと、派生と書くべきところで継承という言葉を使っている箇所があまりにも多数あった。これはまずい。

「DerivedクラスはBaseを継承しているから~」とか、「継承クラス」とか、「publicで継承」などと使っている。どうやら無意識に使っていたらしい。

現実世界では、派生と継承は、明確に使い分けられていない。一体どのように参考書を書けばいいのだろうか。もし、厳密に言葉を使い分けるとすると、やや見慣れない文章になってしまう。というのも、派生という単語を動詞として用いる場合は、「Derivedクラスは、Baseクラスから派生されている」というように、必ず受身で使わなければならないからだ。あるいは、「Derivedクラスは、Baseクラスの派生クラスである」などのように、名詞として使わなければならない。すでに書いた文章を修正しているが、どうも派生という言葉を厳密に正しく使うのは、たまに違和感を覚える。

思うに、自然言語は、規格の文章ほど厳密でなくてもいいということなのだろう。規格の文章では、同じ意味を表す用語が複数あるのは、混乱を招くだけである。しかし、自然言語では、同じ意味を表す言葉がひとつしかないというのは、むしろ稀である。ニュースピークなどという言語は、いかに共産主義がはびころうとも、決して根付くことはないであろう。この点は、一安心だ。

2010-11-27

ネット薬物詐欺「S売ります」で塩送った

ネット薬物詐欺「S売ります」で塩送った - 社会ニュース : nikkansports.com

違法薬物売買用のネット掲示板を多数開設したとして、覚せい剤取締法違反(営利目的譲渡ほう助)で兵庫県警薬物銃器対策課に逮捕、起訴された無職男(36)が調べに対し、自身も偽密売情報を書き込み、1500万円近く稼いだと供述していることが26日、分かった。覚せい剤の購入希望者には塩を、大麻には茶葉を郵送していたといい、まさに「偽違法薬物詐欺」といった手口。ただ“被害者”が名乗り出にくいためか、詐欺容疑での立件はされていない状態という。

しかし、実際Sの注文者に対しては塩を、クサに対しては茶葉を郵送。その結果「1500万円近く稼いだ」と話したという。

これは天才だ。しかも、詐欺では現在のところ立件できず、単に掲示板を解説したことによる幇助罪だけとは。1500万稼いだとあるので、おそらく、脱税も入るのかもしれない。

abstract classで知らなかったこと、付記、派生と継承の違い

以下のコードはwell-formedである。

struct Non_abstract { virtual void f() { } } ; 
struct Abstract : Non_abstract { void f() = 0 ; } ;

abstractクラスは、abstractクラスではないクラスから派生されることができる。その際、pure virtual functionではないvirtual functionを、pure virtual functionとしてオーバーライドすることができる。

これが何の役に立つのか分からない。ただ、pure virtual functionがあればabstract classであるなどという、あまり文法的に美しくないC++の仕様からすると、わざわざこの挙動を禁止する理由が見当たらなかったのだろうか。

ところで、今まで私は、派生と継承の違いを明確に理解していなかった。実際、この二つの言葉は、一般に、あまり区別されていないように思う。では、C++の規格ではどうなのか。

まず、派生というのは、derivedの訳語である。継承というのは、inheritedの訳語である。

規格では、あるクラスは、基本クラスから派生される(be derived from)という表現を用いている。個人的に、受身の表現は分かりにくい。例えば、「DerivedクラスはBaseクラスから派生されている(The Derived class is derived from the Base class.)」といえば、以下のようなコードを意味する。

struct Base { } ;
struct Derived : Base { } ;

ところで、このような場合、俗に、「DerivedはBaseを継承している」などと言われることもある。これは、規格に照らし合わせると、誤りである。継承という言葉は、クラスの派生関係には用いられない。C++では、クラスに対して、継承という言葉を用いるのは誤りである。

では、継承とは何か。規格では、基本クラスのメンバーは、派生クラスに、継承される(be inherited by)という表現を用いている。例えば、「Baseクラスのメンバー関数fは、Derivedクラスに、継承されている(The Base class's member function f is inherited by the Derived class)」といえば、以下のようなコードを意味する。

struct Base { void f() ; } ;
struct Derived : Base { } ;

派生の場合と同じく、このような場合に、「Baseクラスのメンバー関数fはDerivedクラスに派生されている」というのは誤りである。このような言葉は、聞いたことがない。思うに、継承という言葉は、派生クラスに対する基本クラスという意味を表す際に、受身にならずに使えるため、クラスの派生関係にも使われてしまったのだろう。

まとめると、クラスは派生するものである。クラスのメンバーは継承するものである。用語は正しく使わねばならない。

2010-11-26

アダム・サヴェッジ、12インチのカミソリを旅客機に持ち込む

僕はいつも、かばんにガラクタを詰め込んでる。いつも、飛行機に乗る前には、かならず鞄の中のガラクタを確認するんだ。中には危険だと思われるものもあるかもしれないし、手に入れるのが難しいガラクタなんかもあるからね。ただし、今日はそういうことするの忘れたんだ。

で、空港に行ってセキュリティチェック受けたんだけどさ、全身スキャナーを通るわけだ。全身スキャナーってのは、なんかチンポ縮む気がしたけどね。で、奴らはこんなものを見逃してたんだよ。12インチのスチール製のカミソリ。おい、どういうこったよ、これ。やつら俺のガラクタを漁っておきながら、こんなものを見逃したんだぜ。ちっぽけなガラクタに文句つけておきながら、これは見逃すってのかい。

こんなもの持ってもう一度飛行機乗るわけにもいかんしなぁ。誰か欲しくない?

Old New Thing:戦うプログラム

What if two programs did this? Practical exam - The Old New Thing - Site Home - MSDN Blogs

このブログを読んだことのない顧客が、次のような質問をしてきた。

我社のアプリをあらゆるウィンドウの上に表示したいのです。たとえ、他のウインドウがtopmostスタイルを使っていたとしてもです。我社のアプリは、 WM_KILLFOCUSとWM_PAINTメッセージで、topmostに設定し、SetWindowPosでウインドウを一番上に引き上げています。その後、念のためSetForegroundWindowも呼び出しています

結果を申しますと、我社のアプリと他のアプリが競合して、お互い一番上に表示させようとし続けます。どうも、他のアプリも同じような仕組みを使っているらしいのです。また、あるアプリなどは、我社の仕組みを打ち負かし、我社のアプリの上に表示されます。(そのアプリは他社のものなので、どうしようもできないのです)

我社は今、すべてのウインドウに対するすべてのメッセージをフックするためのDLLを書いていて、さらに[ここに書くべき価値もない馬鹿げたトリック]もする予定です。しかし、今の実装では、フックした他のアプリをクラッシュさせてしまうのです。我社は、タイマーを使ってSetWindowPosを周期的に呼び出すことも検討しているのですが、それは非効率的だと思うのです。

この顧客はWhat if two programs did this?のような思考実験すらできないようだ。思考実験のかわりに、実際に実験してしまうとは驚きだ。実験結果は、ただ予想通りというしかない。二つのプログラムがお互いに、一番上になろうとして戦うのである。誰も勝てはしない。皆負ける。とくに、最大の敗者はユーザーである。

ときどき、なぜこんなバカなことをする人間がプログラミングをできるのか、本気で考え込んでしまう。

2010-11-25

Old New Thing: 自前のメール鯖なんて使うわけないだろ

But who's going to set up their own email server? - The Old New Thing - Site Home - MSDN Blogs

昔、まだマイクロソフトのメアドが!を含んでいた頃、マイクロソフト社員の給与明細や保険などの社員情報をオンラインで閲覧、更新するための内部ツールが開発された。ペーパーレス会社へようこそ!

僕の友人は、ツールの説明に、奇妙な一文があるのに気がついた。「プログラムを実行する前に、メールサーバーにログオンした状態にしてください」

「妙だな」と友人は思った。「メールサーバーに接続するのに、何の意味があるんだ。このツールはメールを使わないじゃないか」

友人はたまたま、マイクロソフトのメール製品のテスターであったため、ある実験を試みた。友人は自前のメールサーバーを立ち上げ、billgという名前のアカウントを作った。そして、そのメールサーバーに接続した状態で、ツールを走らせた。

ようこそ、ビルゲイツ様。あなたの社員情報の一覧です。

「おいおい」と友人。「こいつァ、ひでぇ、セキュリティホールだな」。ツールはどうやら、メールサーバーに、「ヘイ、お前は誰としてログインしているんだい?」と訪ねているようであった。その答えは、ツールを実行している者であるという前提である。サーバーは何でもいいのだ。

友人は人事部の部長にメールを送り、この問題を知らせた。「このツールをすぐに利用停止すべきだ。誰でも、他人の個人情報を閲覧できるセキュリティホールがある」と。

人事部の部長からの返事は、あっけからんとしていた。「こちらの開発者が言うには、ツールはセキュアである。どうぞお気軽に社員情報をオンラインで更新してください」

この返事にムカついたため、友人はメールサーバーに新たなアカウントを作成した。人事部の部長と同じ名前のアカウントである。そののち、友人は別のメールを送った。

「貴殿の先の決定を御一考下さるべく申し上げます。貴殿の基本給はXXXドルであり、細君の名前はYyyyであります。ところで、ご子息の十歳の誕生日まで、ちょうど、あと一週間と相成りました。まさに来月であります。」

即座に返信が来た。「この問題を調査中です」

その後すぐに、ツールは、「メンテナンス」という理由で取り下げられた。

2010-11-24

hidingという概念は難しい

struct Base
{
    virtual void f( int ) ;
    virtual void f( float ) ;
} ;

struct Derived explicit : Base
{
    void f( int ) override new ;
} ;

Derived::f(int)には、overrideとnewが両方必要である。virtual関数であるBase::f(int)をオーバーライドしているので、overrideが必要になる。また、Base::f(float)という名前を隠しているので、newが必要になる。どちらが欠けても、コンパイルエラーになる。

ちなみに、派生クラスでベースチェック(explicitキーワード)を使う場合、基本クラスはうかつにメンバーを追加できなくなる。なぜならば、メンバーを追加するということは、派生クラスの前提を変えるということなのだから。

struct Base
{
    virtual void f( int ) ;
} ;

struct Derived explicit : Base
{
    void f( int ) override;
} ;

このようなクラスがあったとして、もし、Baseクラスに、fという名前のオーバーロード関数を付け加えた場合、Derivedクラスの方も、修正しなければならなくなる。

もちろん、これは当然である。そのための明示的なベースチェック機能なのだから。

2010-11-20

平方根のアルゴリズム

平方根である。sqrtである。私の数学知識は非常に乏しく、かろうじて平方根の何たるかを解するばかりであるが、ふと、平方根を計算するアルゴリズムが知りたくなった。理由は、constexprなsqrtを実装してみたくなったからだ。

日本語では、いい情報がWeb上に存在しないので、ここに書いておく次第。この説明は、私のように数学の知識を持たない人間にも理解できるはずである。

ここで使うのは、バビロニア人の方法(Babylonian method)と呼ばれている、歴史あるアルゴリズムである。この方法は、手動でも、プログラミングでも、非常に簡単に計算できる、大変便利で汎用的なアルゴリズムである。しかも、速度もそれほど遅くない。

√Sに対して、

  1. 任意の正の整数を初期値X0と定める(できるだけ平方根に近い値が望ましい)
  2. Xn+1を、Xnと S / Xnの平均値とする(平均値は相加平均で求める)
  3. 必要な精度が得られるまで、ステップ2を繰り返す

では、さっそく手動で計算してみよう。今、√123を求めたいとする。

上のアルゴリズムに当てはめると、S = 123である。x0は、とりあえず1とする。すると

x1 = ( x0 + 123 / x0 ) / 2 = ( 1 + 123 / 1 ) / 2 = 62
x2 = ( 62 + 123 / 62 ) / 2 = 31.9919
x3 = 17.9183
x4 = 12.3914
x5 = 11.1588
x6 = 11.0905

たったの6回の計算で、それなりの精度の平方根を求められる。

さて、これをコードに落としこむ際に、初期値をどう決めるかという問題がある。アルゴリズム的には、正の整数でさえあれば、正しい答えは出る。しかし、ここで条件分岐などを用いて複雑な方法で初期値を決めてしまっては、本末転倒である。大抵のsqrtの実装では、できるだけ簡単な値が選ばれる。たとえば、Sの二分の一など。次に、何度ステップを繰り返すかということであるが、これは、そもそも浮動小数点数の性質からして、値を正確に表すことができないので、単に、前回の値を比較するという方法を取る。つまり、値を比較して差がわからなければ、もうそれ以上ステップを踏む必要がないということである。

namespace hito {

double sqrt( double s )
{
    double x = s / 2.0 ; // Is there any better way to determine initial value?
    double last_x = 0.0 ; // the value one before the last step

    while ( x != last_x ) // until the difference is not significant
    { // apply Babylonian method step
        last_x = x ;
        x = (x + s / x) / 2.0 ;
    }
    
    return x ;
}

}

さて、この関数をconstexpr関数にするのは、簡単である。単に副作用をなくし、ループを再帰で置き換えればいいのだ。

namespace hito
{
    constexpr double sqrt_impl( double s, double x, double last )
    {
        return x != last ? sqrt_impl( s, (x + s / x) / 2.0, x ) : x ;
    }

    constexpr double sqrt( double s )
    {
        return sqrt_impl( s, s / 2.0, 0.0 ) ;
    }
}

ただし、コンパイル時に平方根を計算したい需要がそれほどあるとも思われない。

さらに詳しく知りたい人のために、有益なサイトを挙げておく。

根本的な計算方法は、Wikipediaに詳しく載っている。

Methods of computing square roots - Wikipedia, the free encyclopedia

具体的なコードで読みたいという人のためには、C++によるコード集もある。ちなみに、この記事は素晴らしい出来で、各アルゴリズムの出典まで明記している。

Best Square Root Method - Algorithm - Function (Precision VS Speed) - CodeProject

予想していた通り、浮動小数点数の内部表現をあてにしたビット演算のトリックがかなりある。中でも興味深いのは、謎のマジックナンバーで減算した後、手動のニュートン法を二回分行うコードである。噂によると、Quake 3を開発した伝説のゲームプログラマー、John Carmackによって発明されたのだと言われている。

2010-11-17

gccにconstexprが実装された

GCC 4.6に、constexprが実装された。constexprについては、特に難しいことはない。単に、関数やクラスを、コンパイル時定数にできるというだけの話である。ともかく、せっかくなので使ってみる。この機能は、細々と解説するより、実際にコードを示したほうが分かりやすいであろう。

まずは、constexprな変数である。

int main()
{
    constexpr int a = 0 ; // OK

    int value = 0 ;
    constexpr int b = value ; // エラー
    const int c = value ; // OK
} 

constexpr指定された変数は、必ずコンパイル時定数になる。変数の初期化子は、定数式でなければならない。constとの違いは、constはコンパイル時定数でなくてもよいのである。constは、初期化子が定数式の場合、定数式になる。そうでない場合、単にconst修飾しているにすぎない。

次に、コンパイル時の数値計算をしてみよう。ここでは、べき乗の計算をすることにする。問題を簡単にするため、指数は正の整数とする。これを、constexpr関数で実装してみる。

constexpr double power( double x, unsigned int y )
{
    return y == 1 ? x : x * power( x, y - 1 ) ;
}

int main()
{
    // 定数式
    constexpr double a = power( 2, 32 ) ;
    // 定数式ではない
    double x = 2 ; unsigned int y = 32 ;
    double b = power( x, y ) ;
}

これは、非常に簡単なconstexprの例である。ご覧のように、constexpr関数は、通常の関数と全く同じように使える。実引数が定数式の場合のみ、結果も定数式となる。実引数が定数式でなければ、コンパイル時ではなく、実行時に、通常通りの関数が呼ばれる。これは、全く同じ内容のconstexpr版と通常版の関数を書く必要がないようにするための仕様である。

constexpr関数の本体は、必ず、{ return expression ; }の形でなければならない。つまり、constexpr関数の本体には、たったひとつのreturn文しか書けない。したがって、条件分岐にはcondition expressionを使い、ループには再帰を使わなければならない。もちろん、constexprを使おうなどと考えているプログラマは、すでに一流のメタプログラマであろうから、再帰には全く抵抗がない。したがって、これは問題にならないといえる。

しかし、constexpr関数の目的は、コンパイル時のべき乗や平方根、三角関数などといった、複雑な数値計算ではない。constexprの目的は、むしろ、もっと簡単な計算にある。重要なのは、constexpr関数の呼び出しは定数式なので、定数式を期待している場所に書けるということである。

さっそく、定数式が必要な場所で使ってみよう。

constexpr int twice( int value ) { return value * 2 ; }

template < int N > struct Foo { } ;

int main()
{
    constexpr int a = twice( 1 ) ;
    int b[ twice( 2 ) ] ;
    Foo< twice( 3 ) > foo ;
}

twiceとは、単に引数を二倍して返すだけの単純な関数である。ここでは、constexpr指定された変数の初期化子、配列の要素数、非型テンプレート実引数で、twice関数を使っている。これらはすべて、well-formedである。

constexpr関数は、数値絡みのプリプロセッサーによるマクロを、完全に置き換えることができる。プリプロセッサーは根本的に邪悪である。いやしくもC++プログラマたるものは、#defineと打つたびに恥じ入るべきである。思うに、プリプロセッサーには、中毒性があるのではないかと思う。現に、私の知るある奇人などは、寝る間も惜しんでプリプロセッサーメタプログラミングに打ち込んでいるそうである。私は何度も。プリプロセッサーは体に悪いからやめた方がいいと忠告したのだが、まるで聞き入れる様子がない。

話がそれた。constexprの真の威力は、まだこれからである。変数をconstexpr指定できるということは、すでに述べた。では、constexpr指定できる型とは何か。それは、「リテラル型」と呼ばれるものである。リテラル型には、三種類ある。まず、intやdouble、ポインターなどといった、スカラー型がある。スカラー型はリテラル型である。次に、リテラル型の配列は、リテラル型である。

ところで、C++には、言語組み込みの文法とユーザー定義のコードとを、なるべく一致させるという理念がある。だから、クラスは通常の変数と同じ文法で宣言できるし、演算子はオーバーロードできるようになっている。また、C++では、初期化リストも取り入れられた。とすれば、クラスも、コンパイル時定数になれてしかるべきではなかろうか。

リテラル型の最後の種類は、ある特別な条件を満たしたクラスである。具体的には、以下の条件を満たす必要がある。

  • trivialなコピーコンストラクターを持つこと
  • 非trivialなムーブコンストラクターを持たないこと
  • trivialなデストラクターをもつこと
  • trivialなデフォルトコンストラクターか、コピーでもムーブでもないconstexprコンストラクターを持つこと
  • 非staticデータメンバーと基本クラスは、すべてリテラル型であること

C++0xでは、コンストラクターをconstexpr指定できるのである。これにより、クラスがリテラル型になる。

具体例を示そう。以下はコンパイル時定数として使用可能なクラスである。

class Integer
{
private :
    int value ;

public :
    constexpr Integer() : value() { }
    constexpr Integer( int value ) : value(value) { }

    constexpr operator int() { return value ; }
} ;

int main()
{
    constexpr Integer size = 5 ; // コンパイル時定数

    int x[size] ; // Integer::operator int()が呼ばれる

    Integer object ; // 通常の実行時オブジェクト
    int y[object] ; // エラー
}

Integer型のオブジェクトsizeは、constexpr指定子が使われているので、コンパイル時定数である。また、int型への変換関数を持っている。したがって、int型の定数式を使えるところでは、どこでも使うことができる。一方、objectは、constexprが書かれていないので、通常のオブジェクトである。

もちろん、Integerにpublicな非staticデータメンバーを追加すれば、そのままクラス外部からでも定数式として使うことができるし、その他の非staticメンバー関数も、constexpr指定できる。

リテラル型のクラスは、夢が広がる機能である。

ところで、ひとつ夢のある話をしよう。constexpr関数の本体の中身は、たったひとつのreturn文でなければならないということは、すでに述べた。ということは、条件分岐をする場合、condition expressionと再帰を使わなければならないのであろうか。実は、もう一つ方法がある。リテラル型の配列型はリテラル型である。ということは、その配列は、constexpr関数の中から使えるのである。また、ポインターはリテラル型である。constexpr関数は、ポインター経由で呼び出すこともできる。すなわち、以下のようなコードが書けるのである。

namespace detail {
    // 演算モードの実装
    constexpr int plus_impl( int x, int y ) { return x + y ; }
    constexpr int minus_impl( int x, int y ) { return x - y ; }
    constexpr int mul_impl( int x, int y ) { return x * y ; }
    constexpr int div_impl( int x, int y ) { return x / y ; }
    // 演算モードのテーブル
    constexpr int (*table[])(int, int) = { &plus_impl, &minus_impl, &mul_impl, &div_impl } ;
}
// 演算モードのためのenum
enum struct Mode { plus, minus, mul, div } ;
// ユーザーへのAPI
constexpr int compute( Mode mode, int x, int y )
{
    return detail::table[ static_cast<int>(mode) ](x, y) ;
}

int main()
{
    constexpr int value = compute( Mode::minus, 1, 1 ) ;
}

やっていることは、古典的なジャンプテーブルである。ただし、このジャンプテーブルは、コンパイル時に行われるという点が、少し変わっている。

訂正:誤って階乗としていたところを、べき乗に訂正。指数を正の整数に限定。

2010-11-16

ようやく3x5と5x3に対するまともな意見が読めた

404 Blog Not Found:3x5=5x3

あれはどう考えても国語の問題に過ぎない。数学に国語を持ち込むというのは全く理解出来ない。

そもそも、小学校で習う整数や小数同士の乗算は、交換法則がなりたつように定義されているはずである。A*B=B*Aが成り立つはずである。それで順序を変えて間違っているというのであれば、そのいわゆる小学校数学の定義を示して欲しいものだ。まさか定義に、皿の枚数だの、りんごの個数だのを持ち込むつもりだろうか。つまり、その数学の定義は、日本語に依存しなければ定義できないということなのだろうか。

そして、この教育が行き着く先は、間違いなく、

ほとんどの子は、自ら正解を探すのではなく、教師に答えを求めるようになる。それは教師に答え合わせしてもらわないと安心できないところまで続く。

となるであろう。憂うべきかな。

しかし、みんなbikesheddingが好きなようだ。というのも、この手の問題は、実に議論しやすいからだ。なぜなら、およそ小学校を卒業した者ならば、一桁の整数の乗算はできる。だから誰もが口を出したがるのだろう。

2010-11-15

C++0xにすごい変更が来た

Batavia会議は、だいぶ興味深いことになった。詳しくは、正式なNのペーパーが出てから解説するが、とにかく、非常に重要な項目をふたつだけ解説する。

まず、attributeによって提供されていた多くのクラスのメンバーに関する機能は、キーワードを与えられた。これは、言語機能は、特別な文法を与えるに値するという思想からである。会議でコンセンサスの得られた文法は以下の通りである。

struct Base
{
   virtual void f() { }
   int x ;
} ;

struct Derived final explicit : Base
{
   virtual void f() override { }
   int x new ;
} ;

機能はattributeで提供されていたものと全く変わらないので、説明は省く。変更点としては、base_checkのかわりにexplicitを使い、hidingのかわりにnewを使うことになった。newは違和感を覚えるかもしれないが、色々考慮した挙句、こうなった。

ちなみに、C++0xでは、メンバーの宣言にinitializerを記述できるので、その場合、以下のようになるだろう。

int x new = 0 ;

どうも初心者を混乱させそうな気がする。

これらのキーワードは本物のキーワードではない。文脈依存キーワード(contextual keyword)と呼ぶべきものである。つまり、ある場所においてだけ、キーワードとして扱われるのである。これにより、finalやoverrideといったidentifierを使うことができる。これは、下位互換性を保つための処置である。これらのキーワードが出現する場所は、識別子をかけない場所なので、実装は可能である。contextual keywordは、すでにC#で使われており、実績がある。

つぎに、暗黙のコピーコンストラクターという問題がある。このブログを読んでいる読者なら、David Abrahamsの、N3153: Implicit Move Must Go(暗黙のムーブ爆発しろ)というペーパーは、とっくに読んでいることであろう。また、Bjarne Stroustrupの、N3174: To move or not to move(ムブるべきかムブらざるべきか。それが問題じゃ)というペーパーも、すでに熟読しているはずである。

Daveが暗黙のムーブは深刻な互換性の問題を引き起こすからやめるべきだと主張したのに対し、Bjarneは、暗黙のコピーでも問題は同じだと主張した。激戦の結果、Bjarneが勝った。

これは非常に大事なことなので、特別に大きなフォントで書いておく。

暗黙のコピーコンストラクターは、ユーザー定義のデストラクタがある場合、生成される。この挙動はdeprecatedである。

非常に大事なことなので、もう一度書いておく。

暗黙のコピーコンストラクターは、ユーザー定義のデストラクタがある場合、生成される。この挙動はdeprecatedである。

つまり、以下のような意味である。

struct X
{
    ~X() { } // ユーザー定義のデストラクター
} ;

int main()
{
    X a ;
    X b = a ; // 警告! deprecated!
}

クラスXには、暗黙のコピーコンストラクターが生成される。ただし、この挙動はdeprecatedである。将来的には、規格から削除されるかもしれない。上記のようなコードを書いてはいけない。

ではどうするか。もちろん、ユーザー定義のコピーコンストラクターを書くこともできる。しかし、もし暗黙のコピーコンストラクターの挙動で問題がないのならば、explicitly-defaultedにすることもできる。

struct X
{
    X( X const & ) = default ; // 明示的なデフォルト化
    ~X() { } // ユーザー定義のデストラクター
} ;

int main()
{
    X a ; X b ;
    a = b ; // 正しいコード
}

したがって、正しいC++プログラマーは、ユーザー定義のデストラクターがある場合には、暗黙のコピーコンストラクターは生成されないものと考えるべきである。その機能はdeprecatedである。deprecatedな機能は使うべきではない。

ちなみに、暗黙のコピーコンストラクターは、ユーザー定義のムーブコンストラクターや、ムーブ代入演算子がある場合にも生成されるが、これも同じ理由でdeprecatedである。

マクスウェルの悪魔、召喚さる

中央大学 | ニュース | 世界初「情報をエネルギーへ変換することに成功」理工学部教授 宗行 英朗と助教 鳥谷部 祥一が記者会見を行いました

召喚というか、むしろ悪魔を実装したというべきなのか。

学生運動に参加していた人間がVIPに現れていたらしい

学生運動やってた元過激派左翼の団塊だけど質問ある? : TRTR(・Д・;)

これは興味深い。

学生運動というものは、いまから四十年ぐらい前の話である。私は、どうしてもこの学生運動というものが、理解出来ない。もちろん、当時の記録はある。どのような暴動が行われたとか、そういう記録は残っている。しかし、何故そんなことをしたのかという理由が、全く理解出来ない。アカの主張は、眉にツバをつけなくても、あきらかにトンデモなのだが、一体何が彼らをそこまで駆り立てたのか。

これは、その時代に生きていなかった人間には、理解出来ないのだろう。

2010-11-14

Nvidia、チップセット事業から撤退

Nvidia: We Are Not Building Chipsets Anymore - X-bit labs

IntelとAMDのCPUに対するチップセットの開発をやめるそうだ。つまりこれで、サードパーティ製のチップセットというのは、存在しなくなる。

もはや、チップセットの性能を云々する時代でもないのか。そもそも、昔はマザーボードといえば、本当に各ハードをまとめる板のようなものだった。今や、ほぼすべてのマザボが、サウンドやUSBやLAN程度は、当然のごとくに搭載している。

しかし、これからはどうなるのだろう。さらに現在のチップセットの機能を、CPU側に統合する方向に進化していくのだろうか。そうなると、最終的には、ひとつのチップで、現在で言うところのCPUもGPUもチップセットもすべて搭載するようになるのだろうか。今はまだ、そのような製品は、組み込みのような分野でしか実用化されていない。

面白い雑学動画をいくつか

カカオ豆からチョコをつくってみた:ハムスター速報 - ライブドアブログ

これは気合が入っている。

カカオ豆からココアを作る動画。

映画の音響ができるまで。

2010-11-13

パーフェクトPHPが発売されたらしい

Togetter - 「書籍『パーフェクトPHP』の中身が本当にパーフェクトらしい(※ただし自社推薦含む) レッドブル24本とセットでどうぞ!」

Twitterによると、パーフェクトな出来らしい。こちらも頑張らなくては。

それにしても、今開催されているBatavia会議の状況が気になる。まさか今頃、ADLに変更が来るとは思わなかった。また、base checkingをattributeにするかcontextual keywordにするかで揉めている。noexcept(auto)も提案されている。

何と時代錯誤なことよ

日本政府とNHK、インターネット回線の受信料の義務化へ:ハムスター速報 - ライブドアブログ

ドイツの国営放送が信じがたい。住みたくない国だ。

2010-11-10

耳嚢

しばらく宇治拾遺物語集を書見せるに、右書を読み終わるによって、今は、耳嚢をぞ読みける。書見なる言葉は、いつごろより使われるやうになつたものか知らず。林太郎君の笑うところの言葉なり。

耳嚢は、当時の世上の話を集めたるものにして、およそ二百年前の文なり。根岸鎮衛(1737-1815)奉行が書きたり。

ともかく、耳嚢の文章は、非常に簡単で読みやすい。私が持っているのは、岩波文庫の第二版なので、当時の校訂者である柳田國男の言葉が、巻頭に載せてある。そのなかで、「わずかに125年しかたっていないのに、もうそのままでは読めない」などと書いてある。根岸の死んだ年は、ちょうど今から225年前にあたる。とすれば、柳田國男と現在とは、100年の隔たりがある。ところで、柳田國男の文章も、現代では、もうそのままでは読めない文章である。

柳田國男は、当時(225年前)は、談話と文章の距離が、今(125年前)よりよっぽど近かったのではないかと書いている。もちろん、耳嚢の文章は、口語とは異なるが、それでも、今(125年前)の語尾だけ見た目だけの言文一致よりは、よほど優れていたのではないかと書いている。興味深いことだ。

2010-11-08

体温が上がると体がかゆくなる

私は物心ついたころから、体温が上がると体がかゆくなるという症状に悩まされている。どのような状況で起こるかというと、強力な冷房のきいた場所から暑い場所に移動したとき、熱い食べ物を食べたとき、風呂に入ったとき、急激な運動、などである。思うに、体温の急な上昇が問題ではないかと思う。

ところが、どうも今年の冬は、さらにひどくなっている。最近、寒くなったので、当然厚着をして出かけているのだが、10分ほど普通に歩いただけで、全身かゆくてたまらなくなる。かといって、外套を着ないわけにも行かない。普通に歩くだけでも体温は上がるのは当然なのだが、昔はここまでひどくはなかった。

かゆみは10分ほどもすれば収まるため、それほど日常生活に支障はないものの、今年は格別に頻度が高い。どうしたことだろう。一度医者にでも相談するべきなのだろうか。

2010-11-07

OldNewThing:時刻合わせの際、日付が違っていると失敗する理由

Why does the Win32 Time service require the date to be correct before it will set the time? - The Old New Thing - Site Home - MSDN Blogs

時刻同期の際に、日付が違っていると、処理は失敗し、次のようなエラーメッセージが返ってくる。「Windowsは時刻をtime.windows.comと同期させる際に、エラーが発生しました。セキュリティ上の理由により、Windowsは時刻を同期できません。理由は、日付が違っているためです。日付を修正して再試行してください」。セキュリティ上のリスクとは何だ?

まず、問題を解決したい人は、エラーメッセージに従うことだ。日付を正しく設定して、再試行すべきである。もし、それでも失敗する場合、時間をある程度近い値に設定すべきである。時刻がある程度近くなれば、timeサーバーと正常にやり取りできる。

閑話休題(それはさておき)、ここでいう、セキュリティ上のリスクとは何か。

一見すると、サーバー側が、時刻があまりにも間違って設定されているクライアントを弾いているように見える。しかし、事実は逆である。クライアントが、悪意のあるtimeサーバーの攻撃を防いでいるのである。

ケルベロス認証プロトコルは、お互いが同じ時刻を使っていることを前提としている。(多少の誤差は許容範囲だが)。もし、攻撃者が、例えばDNS poisoningなどで、クライアントの時刻を、悪意あるサーバーと同期させた場合、攻撃者は不正な時刻(大抵は過去の時刻)を用いて、次の攻撃の足がかりにすることができる。

Windows Timeサービスのデフォルトの設定では、15時間以上も違っている日付を拒否するようになっている。このKB記事に従えば、設定を変更することもできる。なお、このKB記事が、本文執筆の主要なソースとなっている。

2010-10-30

cookieの歴史と欠点

lcamtuf's blog: HTTP cookies, or how not to design protocols

これは面白い。

AdobeとMcAfeeはクソだ

今日、突然、画面上に不思議なウインドウがでた。何事かと思ってよく見ると、何とMcAfeeであった。おかしい。私はMcAfeeをインストールした覚えなどない。それに、このウインドウは、ブラウザのポップアップでもない。明らかに独自のウインドウである。南無三、やられたか。これはMcAfeeのフリをしたmalwareに違いない。しかし何故だ。そもそも最近は、ネット上から実行ファイルをダウンロードして実行ということすらしていないはずだ。

ともかく、どのようなプロセスなのか調べることにした。すると、なぜかファイルパスがProgram Files下にある。よく作ったものだ。まるで本物のMcAfeeのようだ。いや、まてよ、Program Files下だと? Program Files下に書き込むためには、Administrator権限が必要である。どうやってUACを突破したのだ。いや、仮にUACを突破したとしても、わざわざProgram Files下に書き込む必要はあるのか。malwareならば、もっと便利な場所がいくらでもあるだろうに。

不思議に思って調べると、スタートメニューにも、McAfeeの項目が付け加えられており、コントロールパネルの「プログラムと機能」にも、McAfeeのアンインストール項目が表示されている。どうもおかしい。偽物にしてはできすぎている。その表示を信じるならば、インストールした日は、2日前である。

2日前といえば、確かFlash Playerのアップデートをしたような気がする。まさか・・・そのまさかだった。クソAdobeは、デフォルトでクソMcAfeeをバンドルしているのだ。しかし、そんなオプション、全く気がつかなかったぞ。クソにも程がある。

つまり、このMcAfeeは本物らしい。Flash Playerのアンインストールを本気で考えてしまった。いずれにせよ、もう数年で、Flash Playerはいらなくなるだろう。

アンインストール後、念のためにMark Russinovichのautorunsを使って調べたが、見慣れない自動実行やサービス、ドライバーの類は見つからなかった。しかしまぁ、なんだかなぁ。

2010-10-29

ニコニコ動画のアカウントを消した

ニコニコ動画を見なくなって久しい。ところが、今日になって、ニコニコ動画からのSPAMメール(連中に言わせると、通知メール)が届き始めた。どうやら、誰かが自分のリストを購読するたびに、SPAMが送られてくるらしい。通知メールを送らない設定にもできるようだが、通知メールの種類があまりにも多く、一つ一つ手動で選択しなければならないという、クソふざけたUIとなっている。しかも、ひとつ設定するごとに、無効にしているメール一覧のページにとばされるので、そのままもう一つ無効にしようとしても、実は有効にしているだけだという始末。

バカにしているにも程がある。即座にアカウントを消した。

思えば、ニコニコ動画は、インターネット史に残るサービスではあったと思う。最初の一年ぐらいは面白かったが、ここ数年は、まともにみなくなっていた。遅い。埋め込み動画はChromeで見れず、一度埋め込み動画を再生しようとしてしまうと、公式サイトに飛んでも、その動画が読み込めなくなってしまう。そもそも、コメントが面白かったのは初期だけで、すぐに、常にコメントを無効にしていたのだ。

結局、ひとつの時代が終わったということか。

C++0xのUnion

C++0xでは、unionの制限がかなり取り払われたので、こんなことができる。

union U
{
    std::string str ;
    std::vector<int> vec ;

    // コンストラクターとデストラクターは、暗黙的にdeleteされているので、
    // ユーザー定義が必要。
    U() { }
    ~U() { }
} ;

int main()
{
    U u ;

    new ( &u.str ) std::string( "hello" ) ;
    std::cout << u.str << std::endl ;
    u.str.~basic_string() ;

    new ( &u.vec ) std::vector<int> { 1, 2, 3 } ;
    for ( auto i : u.vec )
    { std::cout << i << std::endl ; }
    u.vec.~vector() ;

}

まあ、なんのことはない。Uのオブジェクトは、std::stringとstd::vector<int>のどちらかを格納できるだけのサイズを持っているし、またアライメント要求なども適切に行われるので、placement newができるという話だ。

最初、~basic_stringと書くべきところを、~stringと書いてしまい、エラーになった。typedef名の弊害と言える。もちろん、テンプレート実引数は省略できる。なぜならば、オブジェクトの型は、コンパイル時に分かっているからだ。

この手のことは、別に新しいテクニックというわけでもないが、自前でストレージのサイズやアライメントを設定せずにすむので、よりポータブルに書ける。

2010-10-28

ドイツ軍の戦車の生産台数を割り出せ!

German tank problem - Wikipedia, the free encyclopedia

第二次世界大戦当時、連合国は、ドイツの戦車の生産台数を知りたかったが、その方法がなかった。

ドイツの戦車には、シリアルナンバーが付与されていた。捕獲した何台かの戦車から、そのシリアルナンバーを知ることができた。さて、このシリアルナンバーは、明らかに、インクリメントされている。すでに知っているいくつかのシリアルナンバーから、ドイツの戦車の生産台数を割り出すことはできぬものか。

そして、実際に、ほとんど同じ数字を割り出したらしい。なかなか興味深い。

今の世の中では、戦車の保有台数を隠すことに、あまり意味はないかもしれないが、極力敵国に情報を渡さないということを考えると、シリアルナンバーはUUIDなどにしておいたほうが無難なのかもしれない。

連合国はどうやってドイツの戦車生産数を割り出したのか - スラッシュドット・ジャパン

ちなみに、こんな話も。当時の日本人とアメリカ人の食事の違いで、大便の量が異なっていたため、誤った推定をしてしまったというお話。

連載 健康談義 第3回目「健康に生きる」

2010-10-26

これが実現したらいいのに

三単現の“s”20年めどに廃止 米・教育局

ただしソースは虚構新聞。ああ、ソースが虚構新聞でなければいいのに。

ほかにも、articleとpluralを廃止して欲しい。

他の言語版:男性複数与格を2018年めどに廃止─ロシアでも言語ゆとり政策 : bogusnews

2010-10-25

ややこしいnoexcept

MLに面白い話題が上がっていたので紹介する。

noexceptには、二つの意味がある。

1. 例外指定としてのnoexcept

void f() noexcept ; // noexcept(true)と同じ
void g() noexcept(true) ; // 例外を投げない
void h() noexcept(false) ; // 例外を投げる

この場合、文法は、noexcept( 定数式 )という文法になる。定数式がtrueと評価されれば、無例外といういみである。

2. noexcept演算子

void f() ;
void g() noexcept ;

int main()
{
    noexcept( f() ) ; // false
    noexcept( g() ) ; // true
}

この場合、文法は、noexcept( 未評価式 )となる。未評価式が例外を投げる可能性があれば、falseを返す。例外を投げないと保証できる場合は、trueを返す。例外を投げる可能性というのは、throw式が含まれているかや、noexcept(true)と指定されていない関数を呼び出すかどうかで判断される。たとえ、実際にはthrow式が含まれていなくても、無例外指定がされていない関数の呼び出しは、falseと評価される。noexcept演算子は、定数式である。

さて、以下の例を考えてみよう。

void f() noexcept( noexcept( g() ) ) ;

これはどういう意味かというと、g()という未評価式が、例外を投げる可能性がなければ、関数fは無例外指定されるという意味である。一方、

void f() noexcept( g() ) ;

これは、g()という定数式が、trueと評価された場合に、関数fは無例外指定になるという意味である。もちろん、g()という式が定数式でなければ、エラーとなる。

この文法はどう考えてもややこしくないか。

実は、以下のような文法も考慮されていたらしい。

void f() noexcept if true ;

ここでは、ifというキーワードを使うことによって、次に定数式を指定している。しかし、noexcept(true)の方が分かりやすいという意見の方が多かったため、こうなった。また、別の拡張で、似たような文法を使いたい時に困るという意見もあった。別の拡張というのは、ほかでもない、明示的なSFINAEである。

2010-10-24

親知らず三週間目

一週間前、つまり親知らずを抜いてから二週間目では、傷はふさがったものの、親知らずを抜いた影響で、親知らずの近くの歯が、何も悪くないのに痛んでいた。抜歯後、三週間もたった今では、痛みはない。しかし、親知らずを抜いた後が穴になっていて、モノを食べると詰まる。結果として、歯磨に苦労する。

盗難バイクを受け取った少年、一切の電子機器の使用を禁止される

Court Rejects Probation Rules On Teen That Ban Him From Using Social Networks Or Instant Messaging Programs | Techdirt

shall not use a computer that contains any encryption, hacking, cracking, scanning, keystroke monitoring, security testing, steganography, Trojan or virus software.

is not to use a computer for any purpose other than school related assignments.

暗号の利用禁止ということであれば、SSLを利用したWebサイトは使用できなくなる。それどころではない。Webブラウザーやメールソフト自体が使用禁止だ。そもそも、WindowsやMacOSやLinuxといったモダンなOSは、暗号技術がふんだんに使われているので、使用禁止である。コモドールでも使うのだろうか。いやしかし、コモドールは暗号フリーだろうか。

それどころではない。テレビやゲーム、DVDなども使用禁止である。大昔の真空管テレビででもない限り、これらの機械には、暗号技術がふんだんに使われている。もちろん、DRMのかかった音楽や動画、電子書籍なども利用禁止である。また、電話も使えないだろう。

電子透かしも、DRMを利用不可能にする。しかし、現在では、多くの音楽CDに、電子透かしが埋めこまれている。つまりこの少年はCDを再生することすらできまい。

キーストロークモニタリングの禁止も厄介だ。なぜならば、現代のほとんどのソフトウェアは、キー入力を監視している。もちろん、OSはまず筆頭にあがる。キーモニタリングをしていないソフトウェアというのは、OSのカーネルのごく一部でしかないだろう。しかし、それ単体では存在できない。そもそも、BIOSからして、キーモニタリングしているではないか。

クラッキングやスキャニングの定義も曖昧である。セキュリティテストには、おそらくファイヤーウォールやアンチウイルスソフトなども含まれるであろう。これらも実に効果的に、OSを使用不可能にしている。あるコンピューターにウイルスが入っていないと断言することはできない。なぜならば、工場出荷段階で、HDDやフラッシュメモリやEPROMにウイルスが混入している可能性があるからだ。

もし、この少年の住んでいる家が、物理的なカギのかわりに、電子キーを用いていた場合、この少年は一人で家に入ることすらできないであろう。

裁判所の命令を守るためには、この少年は現代技術を排斥するアーミッシュ - Wikipediaの住んでいる場所に引越して暮らすしかないであろう。しかし、アーミッシュとて、道交法をまもるためにしかたなく、馬車にライトを取り付けたりしているのだ。果たしてそのライトには、一切のコンピューターと認められる電子回路が組み込まれていないものかどうか、心配である。

このように、現代社会における暗号の禁止は、単なるパソコンの利用の禁止以上の、あらゆる電子機器の使用禁止という意味を持つ。あらゆる電子機器の使用を禁止された場合、すでにその存在に依存した社会では、暮らしていけないだろう。一体どうしたらこんな馬鹿げた命令を下せたのか、理解に苦しむ。

詳しくは元ソースを参照してもらいたいが、これには抜け穴があって、「学校の宿題のために、学校内や家庭内の監視された環境なら使用可能」という文章がある。おそらく、あらゆる電子機器の利用が、学校の宿題という名のもとに行われるのであろう。そもそも、自宅のドアを自力で開けられなければ、専属の秘書でも雇わない限り、学校に登下校できないわけだし。

そもそも、「盗難バイクを受け取った」という罪が、どうしてコンピューターの使用不可という命令になるのか分からない。現代社会は、コンピューターなしでは、到底暮らしていけないというのに。たとえば、銀行にも行けない。信号機の利用はコンピューターの利用になるだろうか。

働く人たちが答える「質問ある?」スレまとめが面白い

働く人たちが答える「質問ある?」スレまとめ - NAVER まとめ

一部、明らかに怪しいものもあるが、そこは、嘘を嘘と見抜く必要がある2ch.netならではだろう。

昔の2ch.netでは、この手のスレは、「某ですが何か?」などというスレタイだったものだが、最近は「某だけど何か質問ある?」という、普通の形に変わってしまっている。これも、2ch.netの大衆化に伴って、2ch語が廃れたためだろう。もっとも、この「某ですが何か?」というのは、あまり真面目なスレには用いられなかった記憶もあるが。たしか、「先行者ですが何か?」とか、「プログレッシブナイフですが何か?」などというスレばかりだったように記憶している。

思うに、隠語というものは、最初は小数の集団の中において使われていたのが、集団が増えるにしたがって、一般化するか、死語となってしまうかの、どちらかになるのであろう。例えば、寿司屋で食べ終えた後にもらうお茶の事を、「あがり」というが、これとて、もとは寿司屋の店員同士の符丁だったわけだ。

2010-10-23

ネズミーランドのサイン

1日でどれだけディズニーキャラにサインをもらえるか | オモコロ特集

中の人はカリグラフィーの練習までしなけりゃならないのか。

そういえば、私は日本人でも珍しい、あのネズミの住む夢の国に入国したことのない人間である。私は小中高とド田舎で暮らしていたが、学校のクラスのほぼ全員は、一度はネズミーランドに行っていた。恐ろしい集客力である。

2010-10-22

nested_exceptionの使い方

nested_exceptionは、例外をネストするための、簡単なクラスである。ユーザー定義のクラスから継承して使うことを想定されている。

struct CustomException : std::nested_exception
{ } ;

int main()
{
    try {
        try {
            try {
                throw 123 ; // 何らかのエラー
            } catch( int e )
            { // ここで、元の例外の値を保持しつつ、別の例外を一時的にthrowしたい
                std::cout << e << std::endl ;
                throw CustomException() ;
            }
        } catch( CustomException e ) 
        {
            std::cout << "CustomException" << std::endl ;
            std::rethrow_if_nested( e ) ; // 例外を処理し終わったので、元の例外をthrowする
        }
    } catch( int e )
    { // 元の例外が、さらに外側のハンドラへ届く
        std::cout << e << std::endl ;
    }
}

では、nested_exceptionの実装どうなっているのか。実は、特別なことはなにもしていない。以下のような実装になる。

namespace std {

class nested_exception
{
private :
    exception_ptr ptr ;
public:
    nested_exception() noexcept
        : ptr( current_exception() ; )
    { }

    nested_exception(const nested_exception&) noexcept = default ;
    nested_exception& operator=(const nested_exception&) noexcept = default ;
    virtual ~nested_exception() = default ;
    // access functions
    [[noreturn]] void rethrow_nested [[noreturn]] () const
    {
        if ( ptr == nullptr )
            terminate() ;
        else
             rethrow_exception( ptr ) ;
    }
    exception_ptr nested_ptr() const
    {
        return ptr ;
    }
} ;

} // namespace std

これは単に、コンストラクターでcurrent_exceptionを呼び出しているだけである。つまり、nested_exceptionを継承しなくても、自前のクラスに同じ機能を組み込むことも可能である。しかし、このコードは、誰が書いても同じようになる。わざわざ自前で書かなくてもいいように、nested_exceptionがある。

しかし、わざわざnested_exceptionを継承するのすら面倒ではないか。そう思った君は、一流のC++プログラマーの素質がある。プログラマーは、怠惰であればあるほど、優れているのだ。第一、自分でコードを書くのは、バグのもとではないか。そういうズボラな一流プログラマーのために、throw_with_nestedという関数が用意されている。これは、実引数のクラスが、nested_exceptionを継承していれば、そのままthrowし、そうでない場合は、自動的にnested_exceptionと、実引数のクラスとを継承した、何らかの型を生成してthrowするのだ。

// 俺様お手製の超スゲー例外クラス
struct My_Ultra_Super_Deluxe_Exception
{
} ;

void f()
{
    try {
        // 例外を投げるかもしれない処理
    } catch( ... )
    {
        std::throw_with_nested( My_Ultra_Super_Deluxe_Exception() ) ;
    }
}

このようにすれば、例えば、以下のように書けるわけだ。

void g()
{
    try {
        f() ;
    } catch( My_Ultra_Super_Deluxe_Exception & e )
    {
        // My_Ultra_Super_Deluxe_Exceptionに対する例外処理
        // ネストしている場合、元の例外を再throwする
        std::rethrow_if_nested( e ) ;
    }
}

このようにすれば、元の例外を保持しつつ、別の例外を投げることができる。ハンドラ側では、ある例外に対する処理を行い、もしネストされていれば、再び例外をthrowすることができる。

throw_with_nestedの実装例は、本の虫: pre-Batavia mailingの簡易レビューを参照。throw_if_nestedも、ほぼ似たようなメタプログラムで実現できる。

もちろん、これらの関数は、すべて自前で実装可能である。ただし、一流のメタプログラマーではない限り、このようなメタプログラミングをするのは難しいので、標準ライブラリが用意されているのだ。

2010-10-20

pre-Batavia mailingの簡易レビュー

ISO/IEC JTC1/SC22/WG21 - The C++ Standards Committee

N3139: An Incomplete Language Feature

関数の実引数に、空の初期化リストを渡せない問題の修正。以下のようなコードがwell-formedになる。

struct S
{
    S( std::initializer_list<int> ) ;
} ;

// デフォルト引数に空の初期化リスト
void f( S s = { } ) ;

int main()
{
    // 関数の実引数に空の初期化リスト
    f( { } ) ;
}

N3140: Cleanup of Pair and tuple

C++0xの新機能に対応させようとしたら、std::pairとstd::tupleの文面がだいぶおかしくなってしまったので、これを統一して修正。

N3142: Adjustments to constructor and assignment traits

has_*_constructorとhas_*_assignというtraitsは、あたかもコア言語的な響きがする。しかし、ライブラリ作者としては、ある型Tがコンストラクターを持っているかどうかは、別にどうでもよい。ライブラリ作者が知りたいこととは、ある型Tに対して、T()とか、T(U)などと書いてよいかどうかである。したがって、hasという名前は相応しくない。

すべてのhas_*_constructorとhas_*_assignという名前のtraitsを、is_*_constructibleと、is_*_assignableという名前に変える提案。

N3143: Proposed wording for US 90

現行のstd::forwardの定義では、以下のコードがコンパイルできない。

#include <utility>

struct Base { Base(Base&&); };

struct Derived
: private Base
{
    Derived(Derived&& d)
        : Base(std::forward<Base>(d)) { }
};

// error: forward can not access Derived's private Base

なぜならば、DerivedからBaseへのキャストは、Derivedクラスの外からは、アクセス指定の制限のため、行えない。すなわち、std::forwardの中では、行えない。この問題は、std::forwardを、lvalue referenceとrvalue referenceでオーバーロードすることによって解決する。また、std::moveのreutrnに、static_castが抜けているので、あわせて修正。

やはりstd::moveのreturnにstatic_castが抜けているのは規格の間違いだったのか。だいぶ前にstd::moveを自分で実装して、おかしいと思ったのだ。

N3144: Wording for US 84

throw_with_nestedの文面の修正。Tがnested_exceptionを継承していない場合、Tとnested_exceptionを継承したクラスが、forwardによって構築されて投げられるらしい。実装例はこんな感じだろうか。attributeを消し、using宣言をtypedefに置き換えれば、gccで動くことを確認。最近書くコードは、こんなのばかりだ。まったくもって実務的ではない。

namespace std {

namespace detail {
template < typename T >
struct unspecified_exception
    : public std::remove_cv< typename std::remove_reference<T>::type >::type,
      public std::nested_exception
{
    template < typename U >
    unspecified_exception( U && u )
        : T( std::forward<U>(u) )
    { }
} ;

template < bool b >
struct throw_with_nested_impl
{
    template < typename T >
    [[noreturn]] static void invoke( T && t )
    {
        throw std::forward<T>(t) ;
    }
} ;

template<>
struct throw_with_nested_impl<false>
{
    template < typename T >
    [[noreturn]] static void invoke( T && t )
    {
        using type = typename std::remove_cv< typename std::remove_reference<T>::type >::type ;
        static_assert( std::is_class<type>::value, "throw_with_nested:T must be a non-union class type.") ;
        throw unspecified_exception<type>( std::forward<T>(t) ) ;
    }
} ;

} // namespace detail

template < typename T >
[[noreturn]] void throw_with_nested( T&& t )
{


    using plain_T = typename std::remove_reference<T>::type ;
    constexpr bool b = std::is_base_of<
        std::nested_exception,
        plain_T >::value ;
    detail::throw_with_nested_impl<b>::invoke( std::forward<T>(t) ) ;
}

} // namespace std

N3145:Deprecating unary/binary_function

名前通り。

N3146:Recommendations for extended identifier characters for C and C++

C++0xでは、Basic source character set外の文字を、識別子として使うことを許可した。具体的にどのような文字が許可されるのかは、実装に依存するが、規格での推奨事項(空白文字は好ましくないなど)を付け加える提案。

N3148 - throw() becomes noexcept (Version 2)
N3149 - From Throws Nothing to noexcept
N3150 - Removing non-empty dynamic exception specifications from the library

名前通り。throw()をnoexceptで置き換えと、Throws: Nothingをnoexceptに変更することと、空ではない動的例外指定を削除。

N3151: Keywords for override control
N3163: Override Control Using Contextual Keywords

Rapperswill会議において、attributeのbase_check、override、hiding、finalは、キーワードで置き換えることが、投票により決定した。問題は、キーワードをどうするかということだ。もちろん、キーワードは、既存のコードの互換性を確保するため、絶対に使われていないような名前でなければならない。そのため、ML上ではbikeshedding(どのように自転車小屋を建てるべきかという、正直どうでもいい議論)が盛んであった。

キーワード案が採用されるならば、とてつもなくuglyなキーワードが採用されることは確実である。ここで、Contextual Keyword(文脈依存キーワード)という案がある。これは、ある名前を、ある特定の場所でのみ、キーワードとして扱うというハックである。JavaやC#が、すでにこれをやっている。このようなハックは、コンパイラーや文法ハイライトの実装を難しくする。ただし、C++はすでに、他の言語とは比べものにならないぐらい実装が難しい言語である。この程度の実装は、他のもっと難しい昨日の実装に比べれば、屁みたいなものである。それに、このような実装をすれば、ユーザー側の負担は全くない。既存のコードを再コンパイルするコストは計り知れないのである。

N3152: Progress guarantees for C++0x

C++0xは、マルチスレッドとデータ競合に関して、Progress guaranteesというものを、全く定義していない。これでは、プログラマがまともにコードを書くことなど不可能ではないか。というNBコメントに対して、progress guaranteesというものを厳格に定義することは、非常に難しいということを説明したペーパー。

N3154: US 19: Ambiguous use of "use"

規格の文面では、useという言葉が使われている。ところで、3.2では、useという言葉を、特別な意味を表す用語として定義している。しかし、文面では、useを一般の英単語としても使っており、区別がつかない。そのため、3.2のuseを、odr-useという特別な用語に置き換えることにする。3.2の意味でuseという単語を使っている文面も、odr-useに置き換える。

N3155 - More on noexcept for the language support library
N3156 - More on noexcept for the diagnostics library
N3157 - More on noexcept for the General Utilities Library

既存の標準ライブラリの中で、noexcept指定できる関数を模索。

N3158: Missing preconditions for default-constructed match_result objects

名前通り。

N3164: Adjusting C++ Atomics for C Compatibility

C1XとC++0xのatomicの互換性の向上

N3165: Allocator Requirements: Alternatives to US88

allocator_traitsの導入によって、allocatorのrequirementsが大幅に減った。では、実際に規格上のrequirementsも弱めるべきか。C++03との互換性はどうするのか。といったことを論じている。このペーパーにおける提案は、LegacyAllocator Requirementsを付け加えるというものである。ちなみに、legacy_allocator_adaptorというwrapper classを追加しようというアイディアは、却下された。

N3166=10-0156 - Destructors default to noexcept

例外指定のないデストラクターは、デフォルトでnoexcept(true)にしようという提案。一般に、デストラクターから例外を投げるべきではない。すでにC++98の段階で、、STLの全クラスは、デストラクターからの例外のthrowを禁止されている。また、STLに渡すテンプレート実引数の型も、デストラクターから例外をthrowしてはならないと定められている。C++0xでは、デストラクターは明示的にnoexcept(false)などを指定した場合のみ、例外を外に投げられるようになる。

N3167=10-0157 - Delete operators default to noexcept

delete演算子を、デフォルトでnoexceptにする提案。当然、deallocation functionも、この影響を受けて、デフォルトでnoexceptになる。

N3168: Problems with Iostreams Member Functions (Amended from US 137)

また誰にも使われないiostreamの修正か!

N3169: A Few Small Library Issues

これも名前通り。

N3170: Clarifying C++ Futures

futureをどのような目的で使うかということに関して、委員の間でも、意見の不一致がみられた。そこで、futureをどのような場合に使うかという例を示す。また、小さな文面の修正も含んでいる。

N3171: Proposed resolution for US104: Allocator-aware regular expressions

regexがbasic_stringに指定するアロケーターに関して、意味を明確化。

N3172: Allocators for stringstream (US140)

stringstreamがbasic_stringに指定するアロケーターに関して、意味を明確化。

N3173: Terminology for constructing container elements (US115)

コンテナーの文面で、要素の構築に関して、CopyConstructibleとMoveConstructible、引数による構築を、事実上、再定義してしまっている。これを、あらかじめ定義された用語を使うように修正。

N3153: Implicit Move Must Go

暗黙的なムーブコンストラクターとムーブ代入演算子の生成は、C++03のコードとの互換性の問題を引き起こす。ゆえに、規格から消すべきである。題して、「暗黙のムーブは死ぬべき」

N3174: To move or not to move

ムブるべきか、ムブらざるべきか、それが問題だ。ここでは、暗黙に生成されるコピーとムーブによる問題点を列挙している。筆者は、たとえ暗黙のムーブがなかったとしても、暗黙のコピーにより、問題は残ることを論じた上で、現状のFCDの文面を保持するべきだと結論している。また、暗黙のコピーは、ユーザー定義のコピー、ムーブ、デストラクターがある場合、生成をdeprecatedにするべきだと提案している。

つまり、この問題は暗黙のムーブだけではなく、暗黙のコピーにも起こりえるのだ。暗黙のムーブが生成されない状況では、暗黙のコピーも、本来、生成されるべきではない。いまからコピーに対してそのような変更を行うのは無理なので、せめてdeprecatedにするべきだと提案している。

N3178: emplace Broken for Associative Containers

現在のemplaceの定義では、連想コンテナには適用できない。この修正は、現時点では、容易ではない。さてどうするかという短いペーパー。そもそも、STLのコンテナーは、現代からみれば、設計が悪いのだ。だからemplaceなんてものが必要になる。やれやれ。互換性ハ神聖ニシテ侵スヘカラス。

N3179: Move and swap for I/O streams (US138)

basic_istream, basic_ostream, basic_iostreamにおいては、ムーブコンストラクターは、実はムーブしない。ムーブ代入演算子も、実はムーブしない。swapも、実はswapしない。しかも、これらの関数はprotectedであり、ユーザーコードからは使用できない。

しかし、これらのクラスはabstract classではないし、ユーザーコードから使用すべき妥当な理由もある。まあ、これもiostreamだ。したがって誰にも省みられることのない修正と言える。

2010-10-18

ロボットダンスもここまできたか

片足で立っている瞬間もある。すごい。

2010-10-17

残すほど価値のあるものはない

マスコミやGIGAZINEが伝えないマジコン規制の本当の恐ろしさ - P2Pとかその辺のお話@はてな

現在、私の知る限り、DRMが掛かっている書籍、ゲーム、音楽、映画などは、残すに価するほどのものはない。だから、残すという話は、私にとってはどうでもいい。DRMをかけたことによって、将来的に困るのは、コンテンツホルダー側である。彼らの作品は残らないのだから、どんなに作品が人気であったとしても、将来、それによって得られたはずの利益が得られなくなるはずだ。

ただし、一体マジコンのごときものを法律で禁止するのは、危険である。所有しているコンピューターを、どのように使おうが、所有者の自由であるはずだ。マジコンが禁止されるということは、その自由を奪うということである。

もっともDSは、自由にプログラミングできないようなコンピューターである。そんなコンピューターは、始めから所有する価値がない。そして、DSというハードも、将来残らないだろう。

IBM PC/AT互換機は、いまだに残っている。これは、彼らが独占的な権利を主張しなかったからである。もし当時のIBMが排他的な考え方をしていたならば、今のIBMのPC市場で地位はなかっただろう。

デスクリムゾンがWindowsに移植されるらしい

伝説のクソゲー『デスクリムゾン』がWindowsに移植&フリー公開決定、「あの仕様」も完全再現 : はちま起稿

あの伝説のクソゲが移植されるのか。

2010-10-16

親知らず二週間目

親知らずを抜いてから二週間。傷はふさがったが、親知らずがあった場所の隣の歯が痛む。つまりは、一番奥の歯ということだ。特に今朝は酷い。

これはどうすべきなのかよく分からない。表面上、虫歯はないようだ。しばらく痛みが続くようならば、もう一度歯医者に良く必要があるのだろうか。

2010-10-15

wired.comによるBjarne Stroustrupへのインタビュー

Oct. 14, 1985: C++ Adds to Programming | This Day In Tech | Wired.com

なかなか面白かった。

Michael J. Fox、Back To The Futureの予告編をリメイクすること

当時の予告編

リメイク

だいぶ頑張ったようだ。それでもやはり、体の震えを完全に止めることはできないらしい。

2010-10-14

VC10は新しいVC6

Visual C++ 10: 10 is the new 6 | VisualStudio | Channel 9

まあ、確かにVC6と同じくらいクソだということは確かだ。一行に数十文字ぐらい書いただけでクソ遅くなるIDE付きなのだから。C++の規格準拠度も、あきれ返るぐらい悪い。実に悪い。

MSVCのランタイムとスレッドとリソースリークの関係

本の虫: いまだに変な宗教が流行っているを書いたところ、どうもこのへんの情報は、あまり知られていないようであるので、できるだけ分かりやすく解説することにした。

Cの標準ライブラリは、恐ろしく古いライブラリである。その設計は、マルチプロセッサ(コア)上で動作するマルチスレッドが当然の現代では、あまりよろしくない。

たとえば、strtokという関数がある。この関数は、引数として渡された文字列を、内部のバッファにコピーする。次のstrtokの引数には、NULLを渡すことで、そのコピーされたバッファから、次のトークンの場所へのポインターを返すのである。

void f( char const * ptr )
{
    char const * p1 = strtok( ptr, " " ) ;
    char const * p2 = strtok( NULL, " " ) ;
}

しかしもし、strtokが複数のスレッドから呼ばれた場合、どうなるのだろうか。引数にNULLを渡して、先程の文字列のコピーから、次のトークンの場所を返してくれることを期待しているのに、別のスレッドによって、勝手に内部の文字列が書き換わってしまっては困る。

この、複数のスレッドから利用しても大丈夫かどうか、ということは、非常に重要である。これをスレッドセーフと呼んでいる。

したがって、あるスレッドがstrtokを呼んでも、別のスレッドの内部バッファまで変更しないように実装しなければならない。これには、スレッドごとに、メモリーを確保する必要がある。

Cの標準ライブラリには、このようなスレッドアンセーフな設計のライブラリが山ほどある。Cの標準ライブラリは、まともなC++プログラマーならば、まず使おうとは思わないだろう。

言うまでもなく、このような設計は、現代ではクソである。当時のプログラマーを問い詰めたいところなのだが、まあ、すでになされたものは仕方がない。今さら互換性を失うわけにもいかないのだ。クソなことにはかわりはないが。

さて、このような、スレッドごとの動的に確保されるメモリーのアドレスを保持しておくための変数が必要になる。Windowsでは、TLS(Thread Local Storage)という仕組みが、OSによって用意されている。これにアドレスを格納しておけばいいのだ。

Windowsには、CreateThreadという、スレッド作成用のAPIが存在する。しかし、MSVCでは、独自のスレッド作成用の関数、__beginthreadexを使用することが推奨されている。これはなぜかというと、標準ライブラリに必要な、スレッドごとのメモリを確保、解放するためである。

では、もしMSVC上で、CreateThreadを用いてスレッドを作成したら、どうなるのか。スレッドごとの動的に確保されたメモリーを必要とする、一部の標準ライブラリは、動かなくなるのだろうか。幸い、その心配はない。MSVCの標準ライブラリの実装は、スレッドごとの動的なメモリーを必要とする関数が呼ばれたときに、TLSを確認し、もし、メモリーが確保されていなければ、その場で確保して、何事もなかったかのように処理を続ける。これによって、「動かない」という最悪の自体を回避できる。

しかし、ここでひとつ、問題がある。その確保したメモリーは、いつ解放すればいいのだろうか。もちろん、スレッドが終了するとき、すなわち、スレッドというリソースが解放される時である。しかし、スレッドの終了をどうやって補足すればいいのか。スレッドの終了を補足する方法は、なかなかにややこしい。

スレッドが、プロセスの終了まで、ずっと生存しているのならば、問題はない。Windowsにおいては、プロセスの所有するリソースは、プロセスというリソースの解放に伴い、自動的に解放されるからだ。プロセスが解放されたとき、後には何も残さない。もちろん、他のプロセスがプロセスハンドルを掴んでいる場合は、プロセスハンドルを維持するためのリソースは生き残っているが、それはまた別の話である。プロセスのスレッドはすべて開放されているが、まだプロセスが開放されていない状態である。

問題は、CreateThreadによるスレッドの生成、一部の標準ライブラリの仕様、スレッドの破棄を繰り返すプログラムである。そのようなプログラムでは、スレッドを生成、破棄するたびに、解放できないメモリーが取り残される。すなわち、リソースリークである。

実は、DLLを使えば、このスレッドの終了を補足するのは、非常に簡単である。なぜならば、プロセスに読み込まれている、すべてのDLLのDllMain関数は、プロセスのあらゆるスレッドの終了時に、DLL_THREAD_DETACH通知を受ける。この通知を使えば、TLSに保存されているアドレスのメモリーを解放できるのだ。

つまり、DLL版のランタイムライブラリを使えば、CreateThreadやThread Poolによって生成されたスレッドから、一部の標準ライブラリを使っても、リソースはリークしない。スレッド終了時に、必ず解放される。しかし、スタティックリンク版は、この方法が使えない。そして、MSVCの実装も、何とかするようには出来ていない。結果、リソースリークする。

そもそも、他ならぬマイクロソフト自身が、スタティックリンク版を使うなと明言したのが、確かVS2005の頃だった。スタティックリンク版のCRT、ANSI版のAPI、Unicode以外の文字コード、Windows XP、x86の32bitコード、IBM PCのBIOS、これらは皆、速やかに滅ぶべきものどもである。いやしくもプログラマーたるものは、実装の美しさを尊ばねばならぬ。特に、64bitコードの関数の呼び出し規約の統一は、涙が出るほどありがたいはずだ。それにも関わらず、旧態依然の古めかしい知識と技術に固執する。愚かなること、これに過ぎたるはなし。

追記:はてなブックマークのコメントより、

前半は良いのだが、後半のCreateThread()でのメモリリークについては、ちょっと最新の仕様とあってない気がする。Windowsは途中からスレッドハンドルをクローズしなくてはならない仕様になった

これはCRTとは何の関係もない話である。これはWin32 APIの仕様だ。この記事は、Windows、MSVC環境下における、スレッドとCRTのリソースリークについて書いているので、Win 32 APIの仕様には特に触れなかった。

ただし、これもスレッドとリークに関連はある。もちろん、CreateThreadで得たスレッドハンドルは、CloseHandleによって解放しなければならない。なぜならば、CloseHandleを呼び出さなければ、まだスレッドハンドルを、そのプロセスで使っているということだからだ。もちろんこれは、CreateProcessにおけるプロセスハンドルにも言えることだ。してみれば、Win32 API全般に関する注意点であって、特にスレッドに限定される話ではない。

写真を取らなくてもよい七つのもの

7 things you really don't need to take a photo of - The Oatmeal

1. 酒場

「このマンゴーティーニ頼んだの、だあれ?」
「あたしに決まってんだろボケ。いまからさ、写真とって世界中に見せびらかそうよ。あたしらがこんなにもバカやってるところをさ。マジでオランウータンみてーじゃん、あたしら」
「マジでチョーサイコー。ゲロ吐くまで飲も飲も」

2. 食べ物

「この食べ物は芸術的で、まさに写真を撮るに値するよな。まあ、ただ単に、俺がいまクソ腹減ってるってだけなのかもしれないけどさ。実際は、たいしたことないんだろうけど」
「ああ、ものすんげーウマそうだ。一生覚えてるだろうな。このマヨネーズポークサンド。我が心の友よ」

3. 風景

「見ろよあの森を。もう感動しかないな。おい、すぐに写真を取れ、マーシャ。その写真を後でどうこうするわけじゃないけど、知ったこっちゃないし、すぐに写真撮ったことすら忘れるけど、そういうもんさ。まあともかく、メモカを滝や山なんかのゴミ写真で埋め尽くそうじゃないか。悪くないだろ」

4. ライブ

「ところで、これは何だい? 見たところ、チカチカ光ってるボケボケの何かの画像のようだが」
「昨夜のライブだよ。僕は、昨日、ライブを生で楽しむかわりに、携帯のクソ品質のカメラで、決定的瞬間を逃さぬように写真を取るのに熱中してたんだ」

5. キス

「僕達の関係がすんげーいいってことを見せつけるために、オットセイみたいに唇をぶつけ合ってる写真をとっておこう」
「オッケー」

6. 車

「珍走団速度まで加速するのに60秒しかかからないんだぜ」

7. 洗面所での自分撮り

[翻訳を諦めた]

相変わらずoatmealだ。ぬこの画像が含まれていないということは評価できる。

2010-10-13

いまだに変な宗教が流行っている

プログラミング :: 高速なプログラムを書く為に :: 初めに

ランタイムとして DLL を使用しない様にしましょう。DLL の設定にすると、 例えば cos や sin 関数を呼び出すのに dll を使用する (本来 CPU の命令 fcos を一回実行するだけの筈) など、 御馬鹿な事になるからです。数値計算に於いて、頻繁に呼び出す基本関数が dynamic link になっているというのは最悪です。

MSVCでスタティックリンクのマルチスレッドのランタイムライブラリを使ってはならない。リソースリークが完全に防げないからだ。DLL版は、DllMainでDLL_THREAD_DETACHを補足することによって、CRTに必要なリソースを開放しているので、リークは起こらない。

そもそも、DLLを使用しない理由というのが、cosやsinというのは、馬鹿げている。/Oiも知らないのだろうか。

/Oi (Generate Intrinsic Functions)

2010-10-12

シカトの語源は花札

「シカト」という言葉がある。意味は「無視」という意味だが、この語源はなかなか面白い。

シカト - 語源由来辞典

花札に由来する言葉で、少なくとも50年の歴史があるらしい。知らなかった。

standard-layoutとlayout-compatible

標準レイアウト(standard-layout)とレイアウト互換(layout-compatible)の条件や、保証されている挙動を詳しく執筆したが、果たして日本人のC++プログラマーのうち何人が、ここまで詳しい解説を望んでいるのだろうかと疑問になった。

実際、この条件と挙動が規格によって保証されているというのは、C++にとって、非常に重要である。つまり、オブジェクトの内部表現に互換性があるというわけで、他の言語とのやり取りにも使える。

しかし、あまりにも厳密な定義は、果たして一般のプログラマーの役に立つであろうか。これらは、多くの場合、「なんとなく動く」とか、「この環境では動く」程度の認識しかされていない。広く一般に、どのような条件を満たせば、どのような挙動が保証されているのかということを把握しているC++プログラマーは少ない。

もちろん、language-lawyerたる私からすれば、全C++プログラマーは、これらの条件と保証される動作を知っておくべきである。そもそも、C++が必要とされる現実的な分野には、これらの挙動には、まずお世話になるはずである。

暗黙のムーブはやっぱやめよう

Implicit Move Must Go « C++Next

暗黙のムーブは深刻な互換性の問題を引き起こすから、削除しようとのこと。

問題点としては、C++03のコードは、暗黙のムーブを考慮せずに書かれてきた。もちろん、暗黙のムーブなんてものは存在しなかったのだから、これは当然である。しかし、以下のような場合、

// well-formedなC++03のコード
// C++0xではill-formed
class C
{
public:
    C() : v(5) { }
    ~C() { std::cout << v[0] << std::endl ; }
private :
    std::vector<int> v ;
} ;

int main()
{
    C a = C() ;
}

C()によって生成される、prvalueの一時オブジェクトは、暗黙のムーブによって、ムーブされる。std::vectorは、ムーブ可能だからだ。しかし、std::vectorをムーブしてしまうと、もはや要素にアクセスすることはできない。しかし、C()によって生成される一時オブジェクトのデストラクターが走る際、メンバーであるvの要素にアクセスしている。これはエラーとなる。

このコードは、C++03ではwell-formedだが、C++0xではill-formedとなる、互換性のないコードである。

やはり、暗黙のムーブは、あまりにも登場が遅すぎたと言わざるをえない。これに対して、いくつか解決方法が考えられた。たとえば、ユーザー定義のデストラクターがあるばあい、暗黙のムーブの生成をしないようにしようというものだ。しかし、その場合でも、やはり互換性の問題がある。ついには、privateなメンバーを持つクラスは暗黙のムーブを生成しないようにしようなどという意見まででてきた。しかし、それでもなお、この問題は解決しない。

というわけで、暗黙のムーブは、残念ながら、ドラフトから取り除くべきだというのが、Daveさんの意見のようだ。ただ、デフォルトのムーブの動作は、なかなか便利なので、例えば = default ;によって、明示的にデフォルト化された場合は、暗黙のムーブを明示的に生成するような機能を残すのもいいのかもしれない、とも言っている。

いずれにせよ、互換性は言語の進化への大いなる障害だと言わざるをえない。言語の普及のためには、どうしても必要なのだが。