2014-07-27

Linus Torvalds、 GCC 4.9.0のコード生成にブチ切れる

Phoronixで知ったが、Linus TorvaldsがGCC 4.9.0のコード生成にブチ切れている。

問題はLinuxカーネルのload_balance()がランダムにパニックを起こすというもので、その原因は、報告者の使っているコンパイラーであるGCC 4.9.0のコード生成がおかしかったという話だ。

Linus様は御自ら生成されたコードを読み給い、平生と変わらぬ調子で物事の道理を示された。

Linux-Kernel Archive: Re: Random panic in load_balance() with 3.16-rc

From: Linus Torvalds
Date: Thu Jul 24 2014 - 14:47:25 EST

On Wed, Jul 23, 2014 at 6:43 PM, Michel DÃnzer <michel@xxxxxxxxxxx> wrote:

>> マイケル、
>> make kernel/sched/fair.s
>> やった結果のファイルを送ってくれないか?
>
> はいよ。gzipした。これでいいといいんだけど
> ところで、俺のツリーは3.16-rc6だ。

オッケー、コード生成みてるんだが、お前のコンパイラはマジで最高にクソだな。

Jakubをccに追加。gcc-4.9.0は致命的にぶっ壊れてるみたいだぜ。

見ろよコレ。お前のコンパイラーはなんか完全にトチ狂ったもの吐いてるぜ。定数とかな。マジで、このコンパイラーは幼稚園を卒園するのすら認められるべきじゃねーだろオイ。マジで「赤ん坊んときに落っこちて頭を打ったナマケモノ」レベルのアホレベルだぜ、コレは。

movq $load_balance_mask, -136(%rbp) #, %sfp
subq $184, %rsp #,
movq (%rdx), %rax # sd_22(D)->parent, sd_parent
movl %edi, -144(%rbp) # this_cpu, %sfp
movl %ecx, -140(%rbp) # idle, %sfp
movq %r8, -200(%rbp) # continue_balancing, %sfp
movq %rax, -184(%rbp) # sd_parent, %sfp
movq -136(%rbp), %rax # %sfp, tcp_ptr__
#APP
add %gs:this_cpu_off, %rax # this_cpu_off, tcp_ptr__
#NO_APP

定数の-136(%rbp)を見ろよ。マジかよ。コンパイラーが吐いてるのは 即 値 だぜ。

誰かGCCにバグ報告しろよ。こりゃマジでぶっ飛んだクソだからな。

だが、定数を吐くのは「バカすぎて耐えられん」程度のことでしかない。本当のバグはこれだ。

movq $load_balance_mask, -136(%rbp) #, %sfp
subq $184, %rsp #,

gccはスタックフレームを作ってるんだが、すでにスタックフレームの奥底に定数を保存した後でやってやがる。

x86-64 ABIはスタックポインターの後に128バイトのレッドゾーンを規定してて、これはその規程の元ならばセーフだ。どうもよくない気がするが(136 > 128)、だが問題は、フレームポインターを読み込むために、"pushq"を4つ%rspを更新するために使っているので、これはレッドゾーンギリギリのかろうじてセーフだ。

しかし、カーネルは-mno-red-zoneでビルドされている。ここではx86-64 ABIのレッドゾーンには従わない。というのも、カーネルモードでは割り込み不可能だし、スタックはレッドゾーンなしで使う。だから、"-mno-red-zone"は「推奨事項」なんかじゃなくて、カーネルに絶対必要な要件なんだよ。にもかかわらずgcc-4.9はバグだらけの一本グソなので無視しやがる。お前がこのバグにぶち当たった理由は、たまたま一命令を実行中に都合よく割り込みにひっかかったからだ(もしくは、似たようなことがすでに何度か起きていて、カーネルのデータ構造をすでにぶっ壊したか)

さて、俺が思うに、このレッドゾーンバグと、GCCがアホすぎて定数を吐くバグは、なんか関係していると思うね。なんか生存解析(liveness analysis)かなにかで、スタックデクリメントをいつ挿入するのかを決定しているが、定数には生存もクソもあったものじゃねーから無視されるとかさ。つまり二つのバグ(「アホみたいな定数吐くバグ」と「レッドゾーンスタックの不正な利用」)がうまく組み合わさったんじゃないかな。よくわかんねーけど。

とにかく、これはカーネルのバグじゃない。お前のコンパイラーが完全にぶっ壊れたコードを生成してる。gcc-4.9.0で誰かがコンパイルしないように警告すべきだし、Debianの奴らはピカピカの新しいコンパイラーをダウングレードするだろうよ。

Jakub、どう思う?

Linus

そして、Linus様は御自らGCCにバグ報告なされた。

Bug 61904 – Incorrect stack red-zoning on x86-64 code generation

Linus Torvalds 2014-07-25 19:01:36 UTC

(In reply to Andrew Pinski from comment #9)

> 問題のあるコンパイラーのバージョンは4.5.0(debug_insnが使われた時)から4.8.3までと、4.9.0と4.9.1だ。

なるほど、問題のあるコンパイラーのバージョンを避ける方法はないわけだ。4.9.0/1には警告を出せるだろうけどな。まだあまり一般的じゃないから。

やれやれ、コンパイル後にテストパスを追加する提案があるんだよ。だが、今のところ、手のひらをかざす(objdump + perl-script)程度のことだ。あまりイケてない。

問題は、こういうのはめちゃくちゃデバッグしにくいということだ。絶対ありえないはずのkernel oopsや破損を引き起こす。今回の問題はたまたまある二人にとって再現性があって特定箇所だったというだけの話だ。他にもあるのか? それを知る方法はない。

とにかく、素早く対応してくれてありがとよ。ただこの分だと既存のコンパイラーもちょっと心配になってきたんだがな。

さすがはLinus様だ。

2014-07-26

ロスレス圧縮アルゴリズムの歴史

History of Lossless Data Compression Algorithms - GHN: IEEE Global History Network

ロスレス圧縮アルゴリズムの歴史がまとめられている。

かなり長いので、詳細はリンク先を参照。

読み終わった感想を一言だけ言うと、特許のせいでいくつものアルゴリズムが発展せずにそのまま死んだということだ。特許は技術革新を阻害している。

キャンプの計画は難しい

この夏はキャンプにでも行きたい。キャンプに行きたければ、自分で企画するのが確実である。しかし、キャンプの企画は難しそうに思える。

まず、告知して人を募集しなければならない。そして、キャンプ場を予約する必要がある。キャンプ場までの移動手段も確保しなければならない。結構面倒な作業が必要そうだ。

キャンプ場では、ロッジのような出来合いの家を借りるのが一番手っ取り早い。クーラーやキッチンも設置されているし、言うことがない。しかし、それは面白いと言えるのだろうか。かといって、テントを設置するとなると、今の時期はとてつもなく蒸し暑くなるだろう。人が増えれば増えるほど不快になっていく。テントを設置する場合は、春か秋にしたほうがよさそうだ。

費用は、10人から20人ほど入れるロッジで、だいたい一日5,6万円ぐらいのようだ。これを10人から20人で割れば、まあ、費用としてはそれほどかからない。後は食材費や交通費ぐらいだろう。

残念ながら、キャンプ場というのは、かなり早めに予約しておかないと、予約で埋まる。二ヶ月ぐらい余裕をもっておいたほうがいいだろう。

2014-07-25

PHPの次のバージョンはPHP 7かもしれない

PHP: rfc:php6

PHPの次のバージョンは、PHP 6ではなく、PHP 7となる可能性があるとのこと。

敬意を説明すると、PHP 6は、次のPHPのメジャーリリースとして、2005年から盛んに開発されていたが、2010年にUnicode実装の難しさから頓挫した。言語でUnicodeを直接サポートする以外のPHP 6向けの機能は、大方PHP 5.3か5.4に取り込まれた。

この経緯のため、既存の多くのドキュメントや参考書などが、すでにPHP 5.xに存在する機能をPHP 6にやってくる新機能として紹介している。このままPHP 6を出すと、すでにPHP 6であると喧伝されているものとはことなるので、利用者が混乱するのではないか。

そういう理由で、PHPではバージョン番号6をスキップして7に行く議論があるそうだ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

そういえば、今日はある有名なドワンゴ社員が社内IRCにURIエンコードされたJPEG画像を発言していた。ドワンゴ社員ともなると、BASE64の脳内デコードはおろか、JPEGの脳内デコードもできるものらしい。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

Linuxカーネルのバグをgit bisectで特定する話

Odd Bits - Tracking down a kernel bug with git bisect

Linuxカーネルのバージョンを3.15に上げたところ、Docker内でのsuやrunuserが謎のシステムエラーで動かなくなった。カーネルのバージョンを3.14に下げると問題なく動作する。明らかにカーネルが影響を及ぼしている。

よろしい、ならばgit bisectだ。git bisectは良いコミットと悪いコミットの間をバイナリサーチして、問題を引き起こしたコミットを見つけてくれる。

しかし、Linuxカーネル3.14と3.15の間には、約15000件のコミットがあるので、git bisectを手動で回すのは現実的ではない。

git bisectには、自動化のための仕組み、git bisect runがある。これは、コミットをチェックアウトした後に、自動でスクリプトを実行して、現在のコミットが良いか悪いか判断してくれる。したがって、自動化するスクリプトさえ書けば、あとは自動でgit bisectを走らせておけるはずだ。

とはいえ、結構面倒だったという。

まず、コミットが良いか悪いか判断するには、現在のコミットのLinuxカーネルをコンパイルして、実行して、Dockerを実行できるほどには構築されたシステムを立ち上げ、Dockerを実行してその中でテストを実行し、その結果を何とかしてビルド環境まで伝えなければならない。docker pullも行うので、ネットワークも必要だ。

元記事の筆者は、何とかしてその自動化環境を作り上げた。

さて、しばらく実行すると、git bisectは悪いコミットを特定したのだが、残念ながら、そのコミットは多数の変更を含むマージコミットだった。確かに、問題をもたらしたコミットには違いないのだが、まだ本当のコミットを特定できたわけではない。

そんなわけで、そのマージに含まれるコミットに対してさらにgit bisectをかけると、問題のコミットが見つかった。

問題の詳細としては、これはユーザースペースのソフトウェアの挙動に変化をもたらすものではあるが、権限の有無の問題であるので、Docker側を直すほうが望ましいとのことらしい。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

N4036があまりにも読みづらい自己満足レイアウトを利用しているので読む意欲が保てず、気分転換に最近読んで面白かった記事を紹介した次第。

そういえば、Ubuntuにはrunuserがないのだな。suで代用できるか。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-24

Pixivに会社見学に行ってきた

とあるきっかけでpixiv社員と知り合ったので、この機会に、Pixivに会社見学をしてきた。

Pixiv社内は、大変にカラフルな環境であった。レゴブロックの形を模した椅子があり、レゴブロックのように積み重ねることができた。

また、机も変わっていて、すべての板がつながっている不思議な配置になっていた。

また、社内には、大昔のゲーム販売店の展示用の巨大なゲームボーイや、任天堂からゲーム販売店に送られた送り状が貼り付いたままのバーチャルボーイが置いてあった。筆者は、当時バーチャルボーイの店頭デモをプレイしたことがある。当時の感想は、残念、の一言に尽きる。

また、Pixivの入り口は、全面的に絵馬が貼り付けてあり、訪問者による絵やメッセージが並んでいた。これは粋な入り口だ。Pixivが提供するサービスと合致していて、実にいい入り口だ。

絵馬に描かれた絵には様々なものがあったが、いったいどうやってこれを描いたのかと疑問に思うほど技巧的な絵もあった。

あるドワンゴ社員の絵馬もあった。Pixivには日々お世話になっているのであろう。

筆者も、C++ Evangelist 江添亮と書き付けておいた。

技術的な話もしたが、PixivはC++は使っていなかった。

ところで、Pixivといえば、初期は社内の一角にメタルラックにマザボやHDDを無造作においたものがPixivを動かすWebサーバーだったそうだが、今はさすがにそうではない。しかし、メタルラックにマザボやHDDを無造作に置いたサーバーは、今のPixivにも存在していた。何でも社内のサーバーとして使われているそうだ。文化が残っているのは面白いことだ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

なぜ昨日のドワンゴ勤務中にこの記事を書かなかったかというと、メガネを忘れたからである。帰宅してから当日中に書くという手もあったが、しかし、すでにPixiv社内で、ドワンゴ勤務中にPixiv訪問ブログを書くと言った手前、やはりドワンゴ勤務中に書くことにした。

ところで、後でドワンゴ社内で聞いた話によると、Pixivにはドワンゴのポーカー部の絵馬もあるという。なんと、それは気が付かなかった。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-21

最近の動向

どうも、先週の月曜日から火曜日にかけて、午前3時頃まで起きていたのが災いしたのか、体調を崩してしまった。その週は、なぜかすこし疲れやすいぐらいの感覚だったのだが、金曜日には明らかに体調に不調を自覚するほどであった。

しかし、不調とはいえ、わずかな頭痛と熱とノドの痛みだけで、体はだるくないし、特に横になる必要も感じない。なかなか変な体調の崩し方をしたものだ。それでも、体調がよろしくないことは確かなので、この三連休は、運動をせずになるべく寝ていた。

さて、月曜日になって、だいぶ体調がよくなったので、たまには最近の自分のことでも書くことにする。

まず、何故か私宛に足袋が届いた。アマゾン経由ではないようだが、誰かが私に送ってきたらしい。雪駄はすでに持っているので、ちょうどいい。

また、最近、新しい料理に挑戦した。豆料理を作ろうと思い、大豆を1kg買ってきて水煮した。

大豆は主に、トマト煮に使った。トマト煮には、大豆の他にも、玉ねぎと人参をいれた。また、ひき肉も入れるとうまい。

それでもどうしても大豆が余ったので、さいごにひじき煮を作った。大豆とひじきと人参をだし汁で煮詰めると出来上がる。やや味付けが濃かったが、初めてにしては上出来と言えるだろう。油揚げを入れてもよかったかもしれない。

ところで、最近、ミートソースを作る機会が多い。ミートソースは、玉ねぎ、人参、セロリをみじん切りしてそれぞれフライパンで炒める。ひき肉も十分な量を炒める。1kgの大きなホールトマト缶を使い、十分に水分がなくなるまで煮込むと、うまいミートソースになる。十分に煮こむのは重要だ。ミートソースは、普通に作れば普通にうまい。一度自分でミートソースを作ると、出来合いのミートソースが食べられなくなる。それにしても、何故東京にはまともなミートソースを出す店に、未だに巡りあえていないのだろうか。

また、最近作った料理としては、白和えがある。白和えというのは、ほうれん草とか水菜とか人参などの野菜に、潰した豆腐を混ぜて、だし汁で味付けするだけの簡単なものだ。美味しいのだが、どうしても作ると量が多くなってしまう。

今回の三連休は、あいにくと体調を崩していたのであまりはかばかしいことはできなかった。なにか新しい料理にも挑戦したかったし、せっかくなのでどこかに遊びに行きたかったのだが、体調が悪くて終日寝ていた。

2014-07-18

2014-05-pre-Rapperswil-mailingのレビュー: N4021-N4029

5月分の論文集も、これで残すところあと21本だ。ただし、7月分の論文集が69本控えている。

[重量級PDF] N4021: A Proposal to Add 2D Graphics Rendering and Display to C++

C++1yに2Dグラフィックライブラリを入れる提案論文。

グラフィックは今や日常のプログラミングに必要である。グラフィックを描画する方法は、標準で用意されているべきである。

現在の提案では、既存のcairoの設計を元に、C++風の変換をして、またインターフェースを現代的なC++に手直しして使うことになっている。

新規のAPIを設計するのはとても手間がかかる。実験的な実装をして、実際に検証する手間は莫大だ。そこで、既存の、すでに実装されていて、実績もあるcairoライブラリを土台にする。

あらゆるプラットフォーム向けのすべての機能を規格化することはできない。そこで、std::threadと同じ手法を取り、ネイティブなハンドルを取得する方法を規定することにした。これにより、C++利用者は、実行環境に依存する機能も使うことができる。これは、すべてが実行環境に依存するライブラリを使うよりよほどいい。

context型とsurface型を統一することにした。surfaceというのは、描画ターゲットであり、画面とか純粋なメモリ領域とか、あるいはファイルや出力ポートといったたぐいのものだ。surfaceへの描画は、contextを経由して行われる。これは、古典的なグラフィックAPIによくある設計だ。しかし、果たして現代でも理にかなった設計であろうか。

contextは、リソースを共有でき、大昔は、メモリの節約に役立つ設計であっただろう。しかし、今では事情が異なっている。

cairoでは、contextは、既存の別のsurfaceに関連付けることはできない。surfaceからcontextを作成すると、contextの寿命は、その作成元のsurfaceに一生紐付けられる。つまり、利用者の視点からすると、わざわざsurface型とcontext型が分離している意味がない。surface型を直接操作すればいいのだ。

そこで、この論文では、context型とsurface型を統一することを提案している。

論文では、ほとんどの型はムーブしかできず、またimmutableな設計を提案している。これは、土台となるcairoが、Cによる明示的なリファレンスカウントという設計であるためで、しかも、GPUリソースというのは極めてコピーが高くつくので、ディープコピーは推奨できない。このライブラリは初心者でも簡単に使えるようになるべきで、そのためには最初からコピーが禁止されていたほうがよいとしている。

なお、この論文では、提案は現時点ではTSを目指しているとのことだ。

N4022: A proposal to add a generalized callable negator (Revision 2)

Negator、つまり、任意個の実引数を転送して、結果を否定する関数オブジェクトのラッパーである、not_fnの提案。

従来のnegatorであるnot1やnot2は、一個、二個の実引数しか転送できなかった。しかも、予め定められたネストされた型名が必要などの制限が強かった。

// 従来の使いづらいわけのわからない意味不明なコード
struct Yes : std::unary_function< int, bool >
{
    bool operator ()( int ) const
    {
        return true ;
    }
} ;

int main( )
{
    auto f = std::not1( Yes{} ) ;
    std::cout << f(0) << '\n' ;
}

これが、以下のように書ける。

// まともでわかりやすくてモダンなC++風のコード
bool yes( int, int, int, int, int )
{
    return true ;
}


int main( )
{
    auto f = std::not_fn( &yes ) ;
    std::cout << f( 1, 2, 3, 4, 5 ) << '\n' ;
}

ああ、可変引数とムーブセマンティクス万歳。

N4023: C++ Extensions for Library Fundamentals, Working Draft

C++の標準ライブラリに対する拡張的な変更の文面ドラフト。これはTechnical Specificationのようなので、これが規格に直接反映されるよう提案されているわけではない。

[PDFとそれ以外のまともなフォーマットも区別すべき] N4024: Distinguishing coroutines and fibers

コルーチンとファイバーの違いを解説している論文。

これから提案されるファイバーとはなにか。コルーチンとはどう違うのかをわかりやすく簡潔にまとめている。

知っている人にはイマサラ何を初歩的なことを言うかという論文のようにみえるかもしれないが、フルスタックエンジニアなど幻想であり、プログラミングの分野があまりにも広いので、C++WG論文にはよく、提案されている技術の初歩的な解説論文も上がる。とてもわかりやすく書かれているので、読むといい。

ファイバーとは、カーネルスレッドの上に構築されるユーザースペースの実行単位のことで、その設計は、可能な限りstd::threadに似せている。ファイバー用のmutexやcondition variableもある。ひとつのスレッドの上で動く複数のファイバーは、協調的なマルチタスクを実現する。

ファイバーのスレッドに対する優位点は、コンテキストスイッチにカーネルを経由しないので、スレッドより高速に実行できる。

しかも、同じひとつのスレッド上で動く複数のファイバーは、同時に実行されることはないので、お互いに競合しない。これは、ひとつのスレッド上の複数のファイバーで共有するデータをロックしなくてもいいということを意味する。

もちろん、欠点もある。スレッドは規格上、いずれ必ず実行が進むという強い保証を与えられている、ファイバーには、そのような強い保証はない。あるファイバーが実行を握ってしまえば、同じスレッドの他のファイバーは実行できない。また、ファイバーがスレッドをブロックする操作を行った場合も同様だ。

これに比べて、コルーチンとは、関数を拡張したものである。したがってそのインターフェースはスレッドに似ておらず、関数の拡張である。コルーチンは中断した関数の実行を継続させるだけで、ユーザースペースのスケジューラーなどはない。

将来提案される予定のファイバーは、Boost.Fiberを元にしている。これは、Boost.Coroutineを使って実装されている。論文では、ファイバーを使ってコルーチンを実装する形もありだとしている。

[PDFを探求する気はない] N4025: Exploring classes of runtime size

さて、これをどこから解説すればいいものか。

この提案論文は、実行時束縛配列データメンバー(runtime bound array data member)という、クラスのデータメンバーとして実行時にサイズが決まる配列を宣言できるようにする提案である。N3875提案とは異なり、そのようなクラス(実行時サイズ型)は、動的ストレージ上にも確保できる。


struct runtime_size_type
{
    std::size_t const array_bound_size sizeof ;
    char array[ array_bound_size ] ;

    runtime_size_type( std::size_t size )
        : array_bound_size( size ) 
    { }
} ;

int main()
{
    runtime_size_type t1(10) ; // OK
    new runtime_size_type(10) ; // OK
}

動的ストレージにも確保できるようにするためには、実装可能な方法で設計しなければならない。今日のC++では、クラスサイズというのは、固定である。sizeof(T)の結果はコンパイル時に決定でき、実行時に必要な処理は何もない。しかし、クラスのサイズが実行時に決まる場合、この常識は忘れなければならない。

論文では、実行時にサイズがきまる型(runtime-size type)を動的ストレージ上に確保する方法として、三段階の手順を提案している。

  1. オブジェクトが必要とするストレージのサイズを決定する
  2. メモリーを確保する
  3. コンストラクターを呼び出す

提案論文では、コンパイラーがオブジェクトのサイズを返す最小の「size関数」を生成できるようにしている。

実行時にサイズが決まる配列のデータメンバーを、実行時束縛配列データメンバー(runtime bound array data member)という。実行時束縛配列データメンバーの添字に与える式を、束縛式(bound expression)という。実行時束縛配列データメンバーの束縛を決めるために使われるデータメンバーを、配列束縛データメンバー(array bound data member)という。


struct X
{
    const std::size_t a sizeof ; // 配列束縛データメンバー
    char b // 実行時束縛配列データメンバー
    [ a ] // 束縛式
    ;
} ;

配列束縛データメンバー、実行時束縛配列データメンバー、束縛式には、それぞれ厳しい制約がある。

束縛式に使えるデータメンバーは、配列束縛データメンバーしか認められない予定で、配列束縛データメンバーは、配置アドレスの低いほうが高い方にアクセスすると未定義とか、配列束縛データメンバーや束縛式が複数回の評価で結果が変わると未定義とか、とにかく制限が多い。

このような厳しい制限によって、コンパイラーはコンストラクターからオブジェクトのサイズを決定するためだけのsize関数を切り離して生成できる。size関数は未規定の回数呼ばれる。

実行時サイズ型をデータメンバーとすることはできる。実行時サイズ型の実行時束縛配列は違法である。

sizeofは、実行時サイズ型に使うと違法である。実行時サイズ型のオブジェクトに対して使うと、そのオブジェクトの実行時のサイズを返す。

実行時サイズ型へのポインターと整数との間の演算は、単項+演算子を除いて、禁止される。単項+演算子が許されている理由は、特に実装上の問題がなく、また禁止する理由もないためだ。

unionをサポートするべきかどうか議論があるが、std::dynarryの自然な実装には実行時サイズ型であるunionを使うので、サポートされていたほうがいいのではないかとしている。

実行時サイズ型をplacement newすることは、当然可能である。もちろん、利用者は十分なサイズのストレージを提供する責務を追っているわけだから、自己責任だ。ただし、すでにコンパイラーによってsize関数が通常のコンストラクターとは分離して生成されているわけだから、あらかじめ必要なサイズを計算するために、size関数を呼び出す方法が提供されていてしかるべきではないか。たとえば、sizeofに実行時サイズ型の直接初期化式を書けば、実行時にsize関数だけが呼び出されるなどの文法はどうか、と論文は書いている。

グローバル変数に実行時サイズ型は、実装可能であるが、より深い考察が必要であるとしている。

テンプレートの存在は、実行時サイズ型に特に影響しない。ただし、従来、あらゆる型に対して合法であった、sizeof(T)という式が、実行時サイズ型の出現によって、違法になってしまう。そのため、型が実行時サイズ型かどうかを調べるtraitsが必要だろう。なお、このtraitsは、そもそもsizeofが違法になるのだから、コンパイラーマジックを必要とせずに、SFINAEによって容易に書くことができる。

なぜこんなややこしく、明示的に配列束縛データメンバーを書かせるのかというと、配列のサイズを格納するデータメンバーを暗黙に生成すると、ユーザーの自由度が損なわれるからだ。例えば、二つの同じサイズの実行時束縛配列データメンバーが欲しい場合、以下のように書ける。


struct X
{
    const std::size_t bound sizeof ;

    char a[bound] ;
    char b[bound] ;

    X( std::size_t size )
        bound( size )
    { }
} ;

もしコンパイラーが愚直にそれぞれの実行時束縛配列データメンバーに対して、暗黙にboundのようなサイズ情報を格納するデータメンバーを定義してしまうと、このような自由度が損なわれてしまう。

この論文を読み終えた筆者の脳内に思い浮かんだセリフとしては、「C++はエキスパートに優しくなりすぎた」というあのBSの発言だ。

N4026: Nested namespace definition

ネスト名前空間定義の提案。

// N4026提案
namespace A::B::C 
{
// ...
}

このコードは、以下のコードに等しい。

// 現在のC++
namespace A {
    namespace B {
        namespace C {
// ...
        }
    }
}

論文は、既存のC++ユーザーがstack overflowのような質問サイトで、ネストされた名前空間をもっと簡単に書く方法はないのかという質問が複数あることを引用して、この文法は、現実にプログラマーの要求があることを示している。また、大きなプロジェクトでは、名前空間が深くネストするのはよくあることである。

これによく似た文法は、C#に存在して、実際に活用されている。

Using Namespaces (C# Programming Guide)

また論文では、現時点でこれを実装しているコンパイラーは知らないものの、Lazy C++という既存のツールが、この変換を行うとして紹介している。

lzzはなかなか面白そうなツールだが、そのような外部ツールの変換に頼ると、ビルドプロセスが複雑になるため、やはり言語に取り入れることが望ましい。

これは一見小粒にみえるシンタックスシュガーだが、ドワンゴ社内でこの提案を紹介したところ、ドワンゴ社員は欲しいと言っていた。

[やる気をそがれるPDF] N4027: Type Member Property Queries (rev 2)

静的リフレクションとして使えるtraitsの具体的な設計の提案。全部を紹介していてはキリがないが、たとえば、

// N4027提案
enum struct E { hoge, hage, fuga } ;

int main()
{
    // 3
    std::enumerator_list_size<E>::value ;

    // "hoge"
    std::enumerator_identifer<E, 0>::value ;

    // hageの値
    std::enumerator_value<E, 1>::value ; 
}

文字列は、text_constantという、定数式で文字列を返すクラステンプレートによって返される。

他にも、クラスのアクセス指定やメンバーの数や名などを得ることができる。

[PDFは扱いづらい] N4028: Defining a Portable C++ ABI

ポータブルABIを規定しようという提案。

これは・・・微妙。いかにもMicrosoftらしい提案と言える。

C++には安定したABIがない。バイナリから外部に公開するインターフェースとしてC++のコア言語機能や標準ライブラリを使うことは、様々な問題がある。

たとえ同じプラットフォームであっても、同じコンパイラーの同じバージョンの互換性のあるコンパイルオプションでなければ、バイナリに正常にリンクできる保証はないからだ。

このために、未だに公にするAPIとしては、C言語を使うことが一般的である。これは極めて悲惨なことだ。Cは型安全でもメモリ安全でもないため、プログラマーはポインターとサイズのペアなどを直接扱わねばならず、極めて間違いの発生しやすい非人間的な作業を強いられる。

COMやCORBAのようなヘンテコな独自仕様が蔓延しているのも、結局、クラスとかvirtual関数を、なんとか安定したABIで使いたいからである。

そこで、ABI安定なコア言語と標準ライブラリを実装依存として規程しようではないか。ABI互換なコア言語は、extern "abi"{ ... }で囲むことで得られる。また、ABI互換な標準ライブラリは、std::abi下に用意しよう。std::abiはstdとほぼ同じであるが、今後のABI非互換な変更はない。

これは、ひとつのコンパイラーの中にバージョンの異なる二つのコンパイラーを内在させ、またバージョンの異なる二つの標準ライブラリを切り替えられることと、何が違うのか。

今はいい。いまのstd::abiは、現在の最新のスナップショットだから、stdとの差はない。しかし、今後標準ライブラリに変更が加えられるにつれ、どんどん差が開いていく。断絶していく。

この提案は、長期的に見れば、確実に負債になる筋の悪い提案である。昔のバージョンのソフトウェアをそのまま使い続けるのと同じ愚行である。

そもそも、バイナリ互換性などそこまでして必要なものか。ソースコード互換性さえあれば足りるではないか。

GCCは、ABI互換性を重視し過ぎるあまりに、GCCは4.9になってもstd::stringがいまだにCopy On Writeだそうだが、それはGCCの意思決定プロセスの問題に思われる。Microsoftがメジャーアップデートごとに互換性を壊してDLL地獄に陥っているのも、やはり彼らの戦略上の問題だ。

中庸を取れないからと言って、この提案は筋が悪すぎる。このような提案に賛同する者は、Visual C++ 6.0でも使っていればいいのではないだろうか。少なくとも安定したABIは得られるであろう。

筋が悪すぎる。長期的にみれば確実に負債になる。何を考えているんだこの提案は。

[最後までPDF] N4029: Let return Be Direct and explicit

何やら格調高い題名の提案論文。

return文は特別である。return文のオペランドから関数の戻り値の型への変換は、暗黙に明示的変換にしようという提案。

以下のコードが合法になる。


struct X
{
    explicit X( int ) ;
} ;

X f()
{
    // 現在のところill-formed
    // N4029提案ではwell-formed
    return 0 ; 
}

これ以上言うことがない。return文に限り、暗黙に明示的変換される。

論文では、戻り値の型はすでに関数宣言に明示的に記述されているのだし、return expr ; という式は、明らかに、戻り値の型をexprで初期化するものであるので、returnは特別扱いしてもよいとしている。

また、上記のコードのコンパイルエラーは、「俺はお前が何をやりたかったのか知ってるよ。俺のエラーメッセージはほれ、何を書けばよかったのかすら出力してるよ。でも、お前が手で書け」となるので、プログラマーはそんな忌々しいエラーメッセージなど見たくはないだろうと、論文には書かれている。

筆者としては、どうもこれは筋が悪いように思われる。やはり明示的な型変換が必要な場合は、明示的に型変換を書かせるべきであると思う。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

先日、ドワンゴが主催した社内ポーカー大会で、宗教戦争を引き起こす悪意ある目的で、きのこの山とたけのこの里を設置したところ、たけのこの里が多数派であり、実際にたけのこの里の方が先になくなった。これは解せないことである。きのこの山はパリパリ香ばしいクラッカーと塊のチョコレートが魅力的である。一方、たけのこの里はパサパサとした舌触りの悪いクッキーに申し訳程度にコーティングされたチョコレートという始末。どう考えてもきのこの山に圧倒的軍配が上がるべきものであるはずなのだが、世の中は不条理に満ちている。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-16

シンガポールの問題ギャンブル国家委員会のワールドカップサッカーでドイツに息子の貯金を全部賭けた啓蒙広告、コメディに終わる

シンガポールの、問題ギャンブルに対する国家委員会(National Council on Problem Gambling)では、ワールドカップに合わせて、ギャンブルによる不幸を啓蒙するための広告を流していた。この広告はシンガポールの国営放送で流されたので、シンガポール人の大半は見たという。

Hey! Guys! Guys! I really can't wait for the World Cup. Who do you think is gonna win it?

My dad said Brazi will win.

No, no, no!, Argentina's gonna win. Because Messi will dribble past everyone.

I wish Spain will win. My whole family supports them.

How about you Andy?

Andy: I hope Germany will win.

Why?

My dad bet all my savings on them.

[Caption]: Often, the people who suffer from probem gambling aren't the gamblers.

[Caption]: Kick The Habit. Stop Problem Gambling.

おい、お前ら、お前ら。オレ、ワールドカップ楽しみだぜ。どこが勝つと思う?

オレのパパはブラジルが勝つって言ってたもんね。

いや、いや、いや。アルゼンチンが勝つに決まってんだろ。メッシがドリブルで全員抜き去るからよ。

スペインに勝ってほしいな。ボクの家族みんなが応援しているんだ。

アンディはどう?

アンディ「ドイツが勝って欲しい」

なんで?

アンディ「パパがボクの貯金を全部賭けちゃったんだ」

キャプション:問題あるギャンブルで被害を被るのは、ギャンブラー以外の人たちである。

キャプション:悪習を断て。問題あるギャンブルをやめよ。

このNCPGによる啓蒙広告は、ワールドカップの優勝結果が決まる前に放送されたので、結果次第ではコメディになってしまうというコメントがあった。

残念ながら、2014年のFIFAワールドカップの結果は、ドイツの優勝で終わってしまったので、この動画はコメディになってしまった。

YouTubeでは、いい投資をしたとか、パパは賢いとか、ギャンブルを始めてみようかな、とかいった皮肉のこもったコメントがあふれている。

NCPGはワールドカップの結果を受けて、以下のようなバナーを用意した。

「お前のパパ勝ったんだろ。貯金返してもらったか?」

アンディ「ううん、パパはやめてくれないんだ・・・また賭けるんだってさ」

博徒が博打で得た金をまた博打につぎ込むのは、よくあることである。

余談だが、シンガポール英語の聞き取りは難航したので、英語に書き起こしておいた。おそらくあっているはずである。

2014-07-15

ドワンゴポーカー選手権

7月14日の夜に、ドワンゴ社内で、ポーカー選手権が行われた。社外からも人を招き、トロフィーを用意して、最強のポーカープレイヤーを決定する戦いが行われた。

ドワンゴには社内同好会としてポーカー部がある。ポーカー部では、トロフィーを用意して、定期的にポーカー大会を開いて、トロフィーを奪い合っている。ドワンゴのポーカー部員も大勢参加したのだが、残念ながら、皆負けてしまった。

こうして、ドワンゴポーカー部のトロフィーは、あわれにも社外のポーカー強者に掠め取られてしまったのであった。これで社外に流出したトロフィーは2つ目になる。ドワンゴのポーカー部員は奪還を息巻いているが、果たしてどうだろうか。

筆者はポーカーはとても弱いので参加せずに、早々に飛んだ落伍者の暇つぶしのために、ボードゲームをしていた。今回は、キャッスルクラッシュというゲームを行った。これは、積み木を破壊していくゲームであり、とても面白い。

ポーカー大会の後、ドワンゴ社員で人狼を行った。人狼とは、村人と人狼がいて、参加者の中から人狼を探し出すゲームである。人狼はその正体を隠している。毎日、話し合いを行ってから投票して、人狼だと疑わしき参加者を一人、血祭りにあげる。人狼をすべて血祭りに上げられれば、村人側の勝利。人狼と同数まで村人が減ってしまえば、人狼側の勝利となる。

筆者は、このゲームがあまり好きではない。ただ、食わず嫌いもどうかと思い、たまたま機会があったので、参加してみた。人狼であるかどうかは、なかなかわからないものだ。しかし、人狼は全員叩き潰さねばならない。そうしなければ村人は勝利できないからだ。

ところで、ポーカー大会の会場に、忘れ物の服が二着残っていた。ドワンゴ社員のものか、社外の人のものかは、まだわかっていないのだが、服の特徴はそれぞれ、

  • フード付き半袖シャツ
  • 黒と裏地が緑のベスト

だそうだ。心当たりのある方は連絡されたし。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴには、ポーカー部以外にも、ボードゲーム部やカードゲーム部(MTGなど)がある。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-12

雑記

ふと気がつけば、もう東京に出てきてから半年たっている。早いものだ。

今年初めの引越と仕事は、筆者の身の上に大変化をもたらすことは予想していた。変化は好ましいことである一方、悪い影響をももたらす可能性があるものだ。

東京に出てから、筆者はいつも以上に、規則正しい生活を心がけている。早寝早起き、食事、運動、休みの日は休む。健康的な精神を保つためには、まず健康的な肉体を保たねばならない。

現在の環境は、少なくとも数年は継続しなければならないのだ。僅かな短期的な作業のために、徹夜などをして心身を潰してしまってはならぬ。

同時に、日常生活に刺激を与えるために、常に何らかの変化を試みている。料理、テント、ハンモックは、その変化の試みの一部だ。

ところで、昨日、ギークハウス秋葉原で、その場で焙煎して挽いて淹れたコーヒーを飲んだ。コーヒーとはこんなにもうまいものだったのかと感動した。やれやれ、本当にうまいコーヒーごときも知らないとは、まだまだ人生の経験が足りないとみえる。

今日は買い物がてら、12kmほど歩いた。今週は全然歩いていなかったので、いい運動になった。

2014-07-11

momonga.vim #6 ドワンゴ開催の告知

momonga.vim #6 in ドワンゴ(あきらかに) - connpass

@supermomongaの企画するもくもくVim会が、8月2日土曜日の午後に、ドワンゴのセミナールームで開催される。

もくもく会なので、皆でもくもくと何かしらVimに関する作業でもする集まりだ。

今回は、なんとあの暗黒美夢王が現れるとのことで、恐ろしさのあまり震えが止まらない。筆者のVim力では太刀打ちできそうにない。

ドワンゴ広告

この記事はドワンゴ退社後に書かれた。

今日、ドワンゴ社内ではA&Wルートビアが売りさばかれていた。社内にはルートビアがあればコードを書く速度が3倍になると豪語するほどのルートビア好きがいる一方、サロンパスの臭いを訴えて顔をしかめる人も多く、両極端であった。

ところで、ドワンゴ社内のテキストエディターのシェア率は、誰も詳しく統計を取っていないのでわからない。Vim利用者は相当の数がいるはずだが。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-10

2014-05-pre-Rapperswil mailingのレビュー

すでに2014-07 post-Raperswil mailingsが公開されているので、レビューを急ぎたいが、さっと読んで終わりにも出来ぬのが辛いところだ。

C++ Standard Evolution Active Issues List
C++ Standard Evolution Completed Issues List
C++ Standard Evolution Closed Issues List

C++の新機能の議論の場である。C++ Evolution Working Group(EWG)で、現在既知の問題、解決済みの問題、議論の結果問題ではないと結論された問題のリスト。

N4013: Atomic operations on non-atomic data

非アトミック型に対するアトミック操作を可能とする提案。

C++11とC11で標準化されたアトミック操作は、アトミック型のオブジェクトに対してしか行えない。オブジェクトはアトミック型であると明示的に宣言する必要がある。

アトミック操作できるオブジェクトを、型システムで管理するのは理にかなっている。標準規格で厳密に制定された挙動の保証を受けられるし、うっかり非アトミック操作してしまうことをふせぐことができるからだ。また、アトミック操作が不可能な場合をなくせる。例えば、アトミック操作をするオブジェクトは適切にアライメントされていなければならないアーキテクチャで、アトミック型ではないために、アトミック操作に必要な厳格なアライメントがされていない場合、アーキテクチャの制約上、アトミック操作はできない。何らかのロックを使って実装しなければならないが、それではアトミック操作の意味がない。

しかし、現実のコードは、C++11、C11以前から書かれているレガシーコードばかりである。ほとんどの既存のコードは、環境依存の方法(gccの__syncやMSVCのInterlockedなど)でアトミック操作を行っている。アトミック操作するオブジェクトは、宣言時に明示的にアトミック型であると宣言されてはいない。このような既存の莫大なレガシーコードを、すべてC++11やC11のアトミック型に移植するのはいかにも無理だ。

具体的な例としては、Linuxカーネルが挙げられる。リーナスはC11のアトミック操作モデルに対して反感を持っている。

ではどうするか。もちろん、一部の環境では、以下のようなコードが動くかもしれない。


int x;
reinterpret_cast<atomic<int>&>(x).fetch_add(1);

しかし、動くという保証はどこにもない。

そこで、この論文では、非アトミック型Tから、atomic<T>に変換できるかどうかを調べられる機能と、実際に変換する機能を、ライブラリとして追加する提案となっている。変換可能かどうか調べる機能は、type traitsで提供され(C11向けにヘンテコなプリプロセッサーマクロでも提供されるかもしれない)、変換機能は、関数テンプレートで提供される(C11向けにヘンテコなプリプロセッサーマクロでも提供されるかもしれない)

[論文のフォーマットはプレインテキストかHTMLに統一されて欲しい] N4014: Uniform Copy Initialization

この論文は、=に続く{ ... }という形の初期化子を、コピー初期化ではなく、直接初期化にする提案をしている。

以下の例を考える。

struct name
{
    explicit name( std::string const &, std::string const & ) { }
} ;

name n1 { "Nobuo", "Kawakami" } ; // OK
name n2 = { "Nobuo", "Kawakami" } ; // エラー

なんで?

n2がn1より危険であるという理由はどこにもない。n1が認められるのならば、n2も認められるべきである。

C++規格から言えば、n1は直接初期化なので合法だが、n2はコピー初期化なので違法となる。しかし、ソースコード上は=がついているかどうかという些細な違いでしかない。

ほぼすべてのプログラマーは、厳密な文法を理解した上でコードを書かないし、当然そうあるべきだ。その上で、多くのプログラマーが、上記のn2がコンパイルエラーになるという問題に出くわし、原因を調べるのに、無駄に時間を浪費している。この問題は、C++にリスト初期化が追加される以前から存在する問題である。C言語畑からやってきたプログラマーは初期化で{ }を使う前には=が必要だという先入観があるので、当然のように=を書いて、この問題にぶち当たる。

プログラマーの貴重な時間を、このような些細な文法上の問題で浪費させるべきではない。

この論文は、= { ... }という形のコピー初期化を、直接初期化と同じように扱う提案をしている。この提案の元では、上記のn2は合法となる。{ }以外の初期化子の挙動は変わらない。

explicitの機能が損なわれることはない。explicitは暗黙の型変換を防ぐ目的で、依然として機能し続ける。

[PDFは予期していない] N4015: A proposal to add a utility class to represent expected monad

optional<T>をより汎用化して、Haskellのモナド風味にしたライブラリ、Expected<E, T>の提案。

optional<T>は、T型か、あるいはT型を格納していないかというライブラリである。これはもう少し深く考えると、T型とT型を格納していないというエラーを示す型とのenumとなる。ということは、もっと汎用化できるではないか、すなわち、T型か、エラー型のどちらかを格納しているenumのような、もっと汎用的なライブラリがあればよいのだ。

ところで、エラー処理について考えてみよう。プログラムを実行中にエラーが起き、そのエラーを上位の呼び出し元に伝える場合の方法について考える。C++では、エラー処理の方法として、関数の戻り値と例外という、二つの方法がある。

関数の戻り値はC言語からある伝統的な方法だ。しかし、関数の戻り値という通信経路をエラー通知に専有されてしまうのは問題だ。しかも、関数の戻り値をいちいちにチェックしなければならず、甚だ面倒である。通常の処理とエラー処理を綺麗に分けることができない。

例外は、エラー通知専用の別の通信経路である。しかし、ある関数がどんな例外を投げるかどうかというのは、関数の宣言や呼び出しからでは分からず、コードを追っていかなければならない。さらに、例外は一旦エラー情報を保存していくとか、スレッドを超えて伝播させることが面倒だ。

この問題は、関数の戻り値と例外を両方使うライブラリによって解決できる。すなわち、結果を通知する値であるT型か、エラーを通知する値であるE型か、そのどちらかを格納するクラス、Expected<E, T>の提案となる。

より正確には、T型か、std::unexpected<E>型のどちらかを格納する。unexpectedというのは、TとEが同じ型であることを許容するためのタグ型である。

以下のコードは、典型的な、エラー通知を例外で行う関数である。

double safe_divide(double i, double j)
{
    if (j==0) throw DivideByZero();
    else return i / j;
}

となる。ゼロ除算を防ぐコードである。これを使う側のコードは、例えば以下のようなものになるだろう。


double f1 ( double i, double j, double k )
{
    return safe_divide( i, k ) + safe_divide( j, k ) ;
}

これをexpectedを使って書き直すと、

enum class arithmetic_errc
{
    divide_by_zero, // 9/0 == ?
    not_integer_division // 5/2 == 2.5 (which is not an integer)
};

std::expected<std::error_condition, double> safe_divide(double i, double j)
{
    if (j==0) return make_unexpected(arithmetic_errc::divide_by_zero); // (1)
    else return i / j; // (2)
}

となる。これを使う側のコードは以下のようになる。


double f1 ( double i, double j, double k )
{
    return safe_divide( i, k ).value() + safe_divide( j, k ).value() ;
}

expectedのメンバー関数valueは、値がある場合は値を、そうでない場合は例外を投げる。

値があるかどうか、明示的に確認することもできる。


double f1 ( double i, double j, double k )
{
    auto s1 = safe_divide( i, k ) ;
    auto s2 = safe_divide( j, k ) ;

    if ( s1 && s2 )
    {
        return *s1 + *s2 ;
    }
    else
    {
    // エラー処理
    }

}

さて、これをmonad風に書くとこうなるそうだ。


expected<error_condition, int> f(int i, int j, int k)
{
    return safe_divide(i, k).bind([=](int q1) {
        return safe_divide(j,k).bind([=](int q2) {
            return q1+q2;
            });
        });
}

これで、値がある場合は値を、値がない場合はexpectedをそのまま呼び出し元に返すようにできる。Haskell厨も大満足。めでたしめでたし。

C++では、lambda式の文法があまりにも冗長すぎるために、悲惨なコードになってしまっている。論文ではこの問題を解決するために、いくつか方法を提示している。

ひとつは、外部の関数としてmapを定義すること


expected<exception_ptr,int> f(int i, int j, int k)
{
    return map(plus,
        safe_divide(i, k),
        safe_divide(j, k) );
}

ただし、これは遅延評価されないし、何より評価順序が未規定である。

これを完全に解決するには、コア言語にHaskellのdo記法風の文法、do式を導入して、以下のように書けるようにすればよい。


expected<error_condition, int> f2(int i, int j, int k)
{
    return (
        auto s1 <- safe_divide(i, k) :
        auto s2 <- safe_divide(j, k) :
        s1 + s2
    );

これはexpected以外にも広く役に立つ。

この論文を読むのは疲れた。

[本記事最後のPDF] N4016: Light-Weight Execution Agents Revision 2

OSの提供するネイティブなスレッドよりは軽い実行単位を提供するライブラリの提案。

N4017: Non-member size() and more

タイトル通り、非メンバー関数としてのstd::size, std::empty, std::front, std::back, std::dataの提案。

たとえば、std::sizeは以下のように使える。


std::vector<int> v(10) ;
std::size(v) ; // v.size() == 10

なぜ必要なのか。可読性と安全性と効率と汎用性のためである。

このように非メンバー関数であれば、たとえば、配列にも使える。


int a[10] ;
std::size(a) ;

配列の場合は、以下のような関数テンプレートを書くことで、サイズを返すことができる。

template <class T, std::size_t N>
constexpr std::size_t size(const T (&array)[N]) noexcept
{
    return N;
}

これは、醜悪なマクロよりも安全だ。

非メンバー関数を使うことにより、様々な型が、共通の方法で操作できることになる。

std::sizeはstd::forward_list向けのオーバーロードがない。これは、多くの利用者はsizeが低数時間であることを期待しているが、定数時間で実装できないためである。

N4018: C++ Standard Core Language Active Issues
N4019: C++ Standard Core Language Defect Reports and Accepted Issues
N4020: C++ Standard Core Language Closed Issues

C++のコア言語で既知の問題、解決済みの問題、議論の結果、問題ではないと判断された問題の一覧。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今日は台風なのでさっさと帰る。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

cc by-nd 4.0: creative commons — attribution-noderivatives 4.0 international — cc by-nd 4.0

2014-07-07

Kickstarterでポテトサラダを10ドルでクラウドファンディングした者が、すでに8000ドルの出資を受けた話

Potato Salad by Zack Danger Brown — Kickstarter

クラウドファンディング用のWebサービス、kickstarter.comで、10ドルの出資を受けたならばポテトサラダを作るという触れ込みで出資を募った者が、すでに8000ドル以上もの出資を受けるという大成功を収めている。

ポテトサラダ

俺はポテトサラダを作るぜ

いや、俺は単にポテトサラダを作る予定だ。どういうポテトサラダを作るかはまだ決めてない。

追記:作った

目標を延長:

35ドル:俺は4倍のポテトサラダを作るぜ。40ドルとは10ドルの4倍ではないが、まあ、出資者への感謝の気持を込めて。

75ドル:ピザパーティ!

100ドル:2種類のポテトサラダのレシピを試すぜ

追記2:報道すべき価値のあるポテト

http://www.cnet.com/news/guys-kickstarter-dream-making-potato-salad-possibly-with-dill/

追記3:ワーオ、お前ら最高だぜ

進捗最高だぜ。こりゃもう帽子をつくるしかねーな。帽子が欲しい人向けに出資枠を増やしたぜ。帽子の見た目に興味がある奴は以下を見れ。

http://www.zazzle.com/i_love_potato_salad_mesh_hat-148005376484063142

目標を延長:

250ドル:高品質のマヨネーズ(自然食品から選ぶぜ)

300ドル:コックを読んでレシピを教えてもらう。

350ドル:もっとポテトサラダを作るのと、あとたぶん3種類目のレシピに挑戦

ニュースになったぜ!

http://www.abc6onyourside.com/news/features/top-stories/stories/mans-potato-salad-plea-takes-off-kickstarter-33010.shtml

新たに目標を延長:

1000ドル:ポテトサラダ作成をストリーミング放送する。

1200ドル:出資者に感謝の意を伝えるための動画を撮影するために人を雇う

延長大目標:

延長して設定した目標を次々に達成していっちまった。もうこれ以上なにをすればいいのかわかんねーや。とりあえず目標額を倍にするしかねーよな?

3000ドル:俺のキッチンは狭い。パーティホールを貸しきってネット民をみんな招待するぜ!(キッチンに入れるのは10ドル以上出資したやつだけな)。ネット民はポテトサラダを愛しすぎだろ。ポテトサラダもネット民を愛していることをみせつけてやろうぜ!!

なんともまぁ。

まあ、kickstarterでよくあるクラウドファンディングの趣旨からは、だいぶ外れる気もするが、コメディアンとしてはとてもおもしろい。金を出資するだけの価値は十分に生み出していると言えよう。

2014-07-05

Qualcommが謎のDMCA取り下げ通知を発行

[Phoronix] Qualcomm DMCA Notice Takes Down 100+ Git Repositories

QualcommがGitHubの100件以上ものレポジトリのファイルに対して、DMCA取り下げ通知を発行したそうだ。

まあ、それが実際に著作権侵害なのであればいいのだが、どうやら報告によると、単にQualcommの著作権表記の文字列だけを検索して機械的に通知を出したと思われる節があるらしい。多くのファイルは、公に公開されているリファレンスコードやサンプルコードだ。まあ、これはまだ著作権を主張するのもわかるが、androidカーネルのソースファイルと同等のものも取り下げられたらしい。ソースファイルには"Qualcomm Confidential and Proprietary"と書いてあるものの、すでにLinux財団の管理下にあるはずのソースコードだという。

Qualcommも映画業界の仲間入りを果たしたらしい。

2014-07-04

2014-05-pre-Rapperswil mailingのレビュー: N4000-N4009

さて、さくさくC++WG論文を解説していく。

[記念すべきキリ番がPDF] N4000: Towards a Transaction-safe C++ Standard Library: std::list

STLコンテナーをトランザクションセーフにするための研究の一環として、std::listをトランザクションセーフに書き直してみた実験の報告。STLコンテナー自体をトランザクションセーフにすることで、ユーザーが明示的にトランザクショナルメモリーのコードを書かなくてもすむ。

実験は、現在提案されているTransactinal Memoryを実験的に実装したGCC 4.9とそのstd::listの実装に対して行われた。

論文によると、十分に実装可能であり、変更は最小限ですんだという。変更の大半は、メモリ確保と解法、swap関数にtransaction_safeキーワードを使うだけだという。

論文では、実装経験の結果持ち上がった問題についても論じている。

size()が定数時間

C++11では、すべてのコンテナーのsize()のオーダーは低数時間であると定められた。これは、std::listをトランザクショナルセーフにする際に、scalableではなくなるという問題を引き起こす。ライブラリ拡張WGのメンバーは、C++11で軽々しくsize()を低数時間にしたのは誤りであったと認めた。議論の結果、この問題に対処するためにsize()のcomplexityを再び変更するなどということは行わないことで合意したそうだ。

size()がconst noexcept

トランザクショナルメモリーは、ロールバックを認めている。ロールバックを行うには、副作用を一時的に保持しておくストレージを確保する必要がある。ストレージを確保しようとして、確保できない場合が発生すると、bad_allocがthrowされるが、それはconst noexceptであるsize()の中で起こる。しかし、const noexceptな関数の中からそれはできない。これに対処するためには、もっと安全な方法で実装を余儀なくされる。

議論の結果、実装に内部的な静的ストレージをロックやトランザクションで保護できる自由を与えればよかろうという方向に向かったようだ。

非安全な処理を行う要素型への対応

std::listの要素型が、コンストラクターや代入の歳に、ロールバックできない副作用(I/Oなど)を引き起こす場合、いったいどうすればいいのか。

議論と経験の結果、実装はそのような非安全な要素型のインスタンス化を阻害すべきではないが、トランザクションのなかでそのようなメンバー関数を呼び出すことを、コンパイラーは禁止すべきであるという。

論文では、GCCでは、多少の変更でこの挙動を実現可能であるとしている。

論文では、この後、std::listに施した具体的な変更内容の説明が続いている。実験的実装をしたstd::listは、以下のGitHubレポジトリにおいてある。

mfs409/tm_stl

[テキストのみのPDFにする理由が一切感じられないPDF] N4001: SG5: Transactional Memory (TM) Meeting Minutes 2014/02/03-2014/05/19

トランザクショナルメモリーに関する会議の議事録

[PDFも消毒だ] N4002: Cleaning-up noexcept in the Library

標準ライブラリにnoexceptを着ける基準を見直す提案。

File System TS Active Issues List (Revision R1)
File System TS Closed Issues List (Revision R1)
File System TS Defect Report List (Revision R1)

Filesystem TSに持ち上がっている問題、解決済みの問題、議論の結果問題ではなかったと判断された既存の問題のリスト。

N4006: An improved std::{unordered_,}map::emplace

std::mapとstd::unordered_mapのemplaceにムーブ可能な値を渡すと、実際にムーブされるかどうかは、未規定である。


std::map<std::string, std::unique_ptr<Foo>> m;
m["foo"] = nullptr;

std::unique_ptr<Foo> p(new Foo);
auto res = m.emplace("foo", std::move(p));

上記のコードを実行した結果、pがムーブされるかどうか、つまりassertに引っかかるかどうかは、規格上、未規定である。emplaceはひょっとしたらpをムーブせずにコピーするかもしれない。

emplace自体を修正するのは難しいので、挙動を保証した、emplace_stableとemplace_or_updateを新たに追加しようという提案をしたのが、N3873だ。

Issaquah会議で議論した結果、emplaceは動くべき(Just Work)だという意見が大勢を占めたので、この提案では、従来ひとつだったemplaceを三つに分割する。

N4007: Delimited iterators (Rev. 2)

ostream_iteraterの改造版、ostream_jointerの提案。

ostream_iteraterは、以下のように使いたくなる。


std::vector<int> v = { 1, 2, 3 } ;
std::cout << "(" ;
std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, ", " ) ) ;
std::cout << ")"

なるほど、これは汎用的なアルゴリズムを適用できて便利だ。しかし、この出力は、以下のようになる。

(1, 2, 3, )

実は、ostream_iteraterのデリミターは、実はデリミターではなくて、サフィックスとでもいうべき動きをするのだ。

そこで、本当にデリミターとして働くostreamのイテレーターラッパーが提案されている。ostream_jointerだ。ostream_jointerを作るためのmake_ostream_jointerもあって、以下のように使う。


std::copy( v,begin(), v.end(), std::make_ostream_jointer( std::cout, ", " ) ) ;

これを実行すると、出力は、(1, 2, 3)となる。

なお、この論文筆者は、学生に課題としてこれの実装を毎年課しているという。

[PDFは同時に粉砕されるべき] N4008: SIMD polymorphism

コンパイル時に最適なSIMD関数を型システムによって選ぶ、SIMDポリモーフィズムの提案。

ある関数があって、その関数に対して、特定の条件に対しては効率的なSIMD関数を生成できるとする。条件というのは、例えば、ループの中で、関数の引数が、固定、線形に変化、不定といった条件だ。これらの条件に対して、最適なSIMD関数を生成する。

論文は、OpenMPなどの既存のSIMD用の実装による経験を元に書かれている。論文では、上記のような条件を記述するための、何らかの文法があるものと仮定して話を進めている。

さて、あるひとつの関数に対して、条件ごとに最適な複数のSIMD関数コードと、安全にフォールバックするための通常関数コードを生成したとする。この複数の関数から、どのようにして、特定の条件に会う最適な関数を選べばいいのだろうか。

コンパイル時条件分岐というと、まずまっさきに思い浮かぶのが、テンプレート実体化とオーバーロード解決だ。残念ながら、この二つのコンパイル時条件分岐は、あまりにも選択が早すぎる。最適なSIMD関数を選ぶための条件は、テンプレート実体化やオーバーロード解決が終わった後、コンパイラーによるデータフロー解析の結果、判明する。したがって、条件が判明した時には、すでに選択が行われてしまっている。

論文では、この選択には、型システムを使うべきだと主張している。関数の集合を、ひとつの型として認識する。もちろん、関数へのポインターも、通常の関数ポインターとは異なる型で、しかもひとつの型として認識する。その実態は、複数の関数が、条件に従って適切に選ばれるのだ。実装は複数の関数の中から、適切なSIMD関数にディスパッチする。適切なSIMD関数を選択するのは、ループの外で行われるので、virtual関数呼び出しのようなパフォーマンスの問題はない。

ひとつの関数から生成される複数のSIMD関数と通常関数のコードは、ユーザーからは完全に一つの型、SIMDポリモーフィズムな型としてみえる。ユーザーが特定のひとつのSIMD関数を個別に参照することはできない(特定の条件で呼び出せば、間接的に選択可能ではあるが)

論文では、通常の関数へのポインターとSIMDポリモーフィズムな関数へのポインターを、相互に型変換できるべきであるとしている。また、相互に等価を比較できるべきであるとしているが、等価比較には、色々とコストがかかり、最適な実装方法がないとしている。

また、複数のアーキテクチャが混在するヘテロコンピューター環境が珍しくない現代、このSIMDポリモーフィズムの機構を使って、実行時に最適なコードを選ぶといった将来性もあるであろうが、この論文では、今回はそれを考察しないと結んでいる。

ただでさえわかりにくい型シムテムを、さらにわかりにくくする提案だ。そして、まだ具体的なSIMD条件を記述するための文法が提案されていない以上、この論文だけではどうしようもない。

N4009: Uniform Container Erasure

コンテナーから条件を満たした要素をすべて消し去り、サイズも変えるerase_if(container, pred)の提案。

以下のように使う。


std::vector<int> v = { 1231, 132, 2321 , 222, 35, 6643, 11, 2, 890, 33} ;

std::erase_if( v, [](auto && elem ){ return elem < 100 } ) ;

// vは{1231, 132, 2321, 222, 6643, 890}

従来、これをするには、以下のように書く必要があった。


v.erase(
    std::remove_if(v.begin(), v.end(),
        [](auto && elem ){ return elem > 100 }
    )
    , v.end()
    ) ;

しかし、もし以下のように書いてしまった場合、意図通りには動かない上に、コンパイルが取ってしまい、実行できてしまう。


v.erase(
    std::remove_if(v.begin(), v.end(),
        [](auto && elem ){ return elem > 100 }
    ) ) ;

これは、STLコンテナーのeraseメンバー関数には、イテレーターをひとつだけ取るオーバーロードと、イテレーターの範囲を取るオーバーロードがあるからだ。コンパイラーはこのミスを警告すらできない。

このため、erase_ifを提案する。

なぜerase_ifはメンバー関数ではないのか。このようなコンテナーごとに最適な実装が異なるアルゴリズムは、従来ならばメンバー関数として実装していたではないか。この理由としては、basic_stringがやりすぎてカオスなことになってしまっているのを反省してのことらしい。

また、名前がややこしいという問題もある。eraseとremoveは意味が似通っていてわかりにくい。論文ではこの疑問に対して、eraseというのは、listとforward_listのような例外を除けば、コンテナーのサイズを変更する場合に一貫して使われている。コンテナーのサイズを変更するremoveはない。また、eraseという非メンバー関数は使われていないとしている。

ただし、やはりわかりにくいとは思う。バイク小屋議論は尽きないものだ。

なぜpredicateだけなのか。なぜ削除すべき値を指定するオーバーロードはないのか。問題は、連想コンテナーとunordered連想コンテナーには、erase(key)というメンバー関数があり、混同しやすいからだとしている。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

この記事を執筆中に、社内の筆者の近所の席から、何やらダースベイダーの呼吸音のような音が聞こえると思ったら、ビーダマン後期の製品、コバルトブラスタードライブキャノンとデストロイドラゴンで遊ぶエンジニアがいた。リモコンで前身と旋回操縦可能な上に、ビー玉単発や連写までできるすぐれものだ。ただし、シメ撃ちはできそうにない。シメ撃ちできないと滝をぶち破ったりできないと思うのだが、いったいどうするのだろうか。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

Ubuntu 14.04のUnityの設定をぶっ壊した場合の修復方法

今朝、コンピューターを起動して、Ubuntu 14.04にログインしようとしたら、なぜか画面が固まってしまった。

まあ、この程度は情報強者たる筆者にとっては、造作もないことだ。Ctrl+Alt+F1で華麗に仮想コンソールに切り替えて、Upstartのinitctlを使ってlightdmを再起動させた。

$sudo restart lightdm

カチャカチャ・・・ターンッ!

restartは、initctl restartの代わりに使えるinitctlへのシンボリックリンクだ。おそらく、Ubuntuも将来的にはsystemdに移行するであろうから、いずれはsystemctlを使う必要があるであろう。だが、それはまだ先の話だ。

Ctrl+Alt+F7で戻ったところ、無事にlightdmによるログイン画面が表示された。さっそくログインしなおしたが・・・Unityがぶっ壊れていた。

背景とマウスポインターは表示される。右クリックするとメニューも表示される。しかし、それ以外のUIが一切ない。ランチャーもメニューバーもないので、このままではGUI作業ができない。GNOMEターミナルを開くキーボード・ショートカットも動かない。

仕方がないので、情報弱者らしく再起動をしてみたが、

$sudo shutdown -r now

Unityは壊れたままだった。

やってしまった。これはおそらく、無理やりlightdmを再起動させたので、どこかの設定ファイルが壊れてしまったのだろう。試しに別のユーザーでログインしてみると、ランチャーもメニューバーも通常通り表示される。しかし、Unityの設定ファイルをぶっ壊してしまったので別ユーザーを使います、というのは情報弱者にもほどがある。さて、どうやって復旧しようか。

あるいは、この機会に、別のWMを試してみるという手もある。しかし、何はともかく、Unityを復旧させたい。

まず、Compizの設定をリセットしようと思い立った。Compizの設定をリセットするには、CompizConfig Settings ManagerというGUIのソフトウェアを使う必要がある。しかし、ランチャーもターミナルもないと、起動することができない。

調べたところ、DISPLAY変数を適切に設定することで、仮想コンソールからプログラムを起動してそのウインドウを望みのディスプレイに表示できるようだ。

$sudo apt-get install compizconfig-settings-manager
$export DISPLAY=:0
$ccsm

無事に起動できたので、Unityプラグインを設定しなおしたり、デフォルトの設定を読み込ませたりしてみたが、残念ながら、これでは直らなかった。さて、どうするか。

さらに調べたところ、unityを起動するラッパーである/usr/bin/unityに、--resetオプションを指定すると、設定ファイルをリセットしてくれるという。

$man unity
unity(1)                              Linux User's Manual                              unity(1)

NAME
       unity - wrapper for starting the unity shell and handling fallback

SYNOPSIS
       unity [options]

DESCRIPTION
       The  unity program can be used to start the Unity shell as a compiz module, and to spec‐
       ify how to handle logging, debugging, as well as how to deal with the user's profile.

OPTIONS
       --advanced-debug
              Runs unity under debugging (using GDB or another debugger tool) to help  tracking
              issues. Should only be used on request from a developper following a bug report.

       --log filename
              This  parameter,  followed  by a path or filename, tells the Unity shell to store
              logs in the specified file.

       --reset
              This option allows the user to reset profile parameters in compiz and restart the
              Unity shell with default settings.

       --verbose
              This  option turns on displaying additional debugging output for the Unity shell.
              It can be used by the user to debug configuration issues. This  option  is  often
              used along with the --log option to save output to a file.

SEE ALSO
       unity-panel-service (1)

                                        9 December 2010                                unity(1)

なるほど、ではさっそく

$ unity --reset
ERROR: the reset option is now deprecated

なんだと。

さらに調べたところ、Ubuntu 14.04では、unity-tweak-toolが公式なレポジトリに入っていて、これにはUnityの設定をリセットする機能があるようだ。

$sudo apt-get install unity-tweak-tool
$man unity-tweak-tool

unity-tweak-tool(1)                   Unity User's Manual                   unity-tweak-tool(1)

NAME
       unity-tweak-tool - configuration manager for Unity desktop environment

SYNOPSIS
       unity-tweak-tool [options]

DESCRIPTION
       The unity-tweak-tool program can be used to tweak Unity desktop environment. Unity Tweak
       Tool is a one-stop settings manager for Ubuntu Unity.

OPTIONS
       -u     Starts unity-tweak-tool in Unity section.

       -w     Starts unity-tweak-tool in Window Manager section.

       -a     Starts unity-tweak-tool in Appearance section.

       -s     Starts unity-tweak-tool in System section.

       --reset-unity
              Reset Unity, wiping all changes to configuration.

BUGS
       Please report any bug you may experience to the unity-tweak-tool developers, who can  be
       reached at https://launchpad.net/unity-tweak-tool.

AUTHOR
       unity-tweak-tool was written by Freyja Development Team and this manual page by Barneed‐
       har Vigneshwar <[email protected]>.

       Both are released under the GNU General Public License, version 3 or later.

                                        11 February 2013                    unity-tweak-tool(1)

これを使ってみよう。

$unity-tweak-tool --reset-unity

これはうまくいった。無事に、Unityが復旧した。

たまに環境が壊れると、刺激があって面白い。動かないものを動くように直す作業は楽しい。しかし、それは危険な誘惑である。

xkcd: Cautionary

Linux: 実際にあった話:第一週

もしもし、あたしあたし、姪だけど。新しいパソコン手に入れたんだけどさ、Windowsとか入れたくないのよ。Linuxとかいうやつのインストール手伝ってくれない?

いいよ

第二週

XORGが壊れたって。XORGって何? どうすればいいの
「manページ教えるよ」

第六週

autoconfigがうまくいかないんでUbuntuからDebianに変えることにする
「えっ」
Gentooにするかも
「やばい」

第十二週

「最近電話に出ないけど」

寝らんない。カーネル、コンパイル、しなきゃ。

「手遅れか」

親に告ぐ:誰か他人に教わる前に、子供にLinuxを教えるべきである。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

昨日、いつも通り午後2時頃にドワンゴに出社したところ、ACアダプターを家に忘れたことに気がついたので、その日はバッテリーが切れる前にさっさと退社した。今日は朝からネタができたので、午前11時に出社した。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-02

妖怪ハンモック

さて、妖怪ハウスにハンモックを導入してしばらくたった。筆者がハンモックを購入した理由は他でもない。夜にハンモックで寝るためである。ハンモックで寝るということには、ロマンがある。

最初に買った、ハンモックを吊るす土台付きのハンモックは、寝っ転がってリラックスするにはよいが、寝具として使うには機能不足であった。そこで、もっと幅が広いハンモックをもう一枚購入した。問題は、二枚目のハンモックは多きすぎて、すでに買った土台には取り付けられない。ベランダの手すりに取り付けることはできるのだが、日光が直接顔面にあたって寝られない。

この問題を解決するために、筆者はビーチパラソルを購入した。幸い、アマゾンには安いビーチパラソルが売られていた。これでハンモックでも快適に寝られるはずである。さっそく、今夜は雨が振らない天気予報であることを幸い、寝心地を試してみようと思う。

ビーチパラソルは、ハンモックの他にも色々と役に立つはずである。

日々変わりない平凡な日常では腐ってしまう。常に変化が必要である。次はどんな変化を試みようか。

2014-07-01

2014-05-pre-Rapperswil mailingのレビュー: N3990-N3999

C++WG論文がたまっているので消化していきたい。

[出だしからPDF] N3990: Adding Standard Circular Shift operators for computer integers

サーキュラーシフト演算子(Circular shift operators)、つまりローテート演算子の提案。

サーキュラーシフト演算子とは、シフト演算子に似ているが、あふれでたビット列が、反対側に現れる。つまり、11110000という8bitの整数を左に2、サーキュラーシフトすると、11000011となる。

ローテート操作は、暗号計算などの分野で多用されているため、高速である必要がある。多くのアーキテクチャでは、ローテート操作をするプロセッサーネイティブの命令が存在する。しかし、C言語では、ローテート操作のための標準的な方法が存在しなかった。そのため、標準C++の枠内で移植性のある実装をするには、既存のシフト演算子を使わなければならない。

GCC 4.7以降では、そのようなシフト演算子を組み合わせたローテート操作を認識し、ローテート命令のあるターゲット向けならば最適化できる。しかし、単にコードを読み書きする都合からも、標準の方法が存在すべきである。

提案されている演算子は、<<<. >>>, <<<=, >>>=の4つである。意味は明らかだろう。この演算子は、もちろんオーバーロード可能だ。

サーキュラーシフト演算子の左辺は、符号なし整数でなければならない。もし、符号付き整数が指定された場合の挙動は未定義である。

void f( int x )
{
    // 挙動は未定義
    x <<< 1 ;
}

サーキュラーシフト演算子の右辺は、正の整数で左辺の整数型のビット数未満でなければならない。右辺が負数であったり、左辺の整数型のビット数以上であった場合の挙動は、未定義である。

// 1バイトは8bitであるとする
void f( unsigned int x )
{
    // 挙動は未定義
    x <<< -1 ; 

    // 挙動は未定義
    x <<< sizeof(x) * 8 ;
    x <<< sizeof(x) * 8 + 1 ;
}

挙動は未定義であって、ill-formedであるとは定められていない。もちろん、未定義であるからして、ill-formedとなっても規格準拠の実装である。ゼロ除算と同じような扱いだ。

[またPDF] N3991: Task Region R2

fork-joinという考え方の並列実行のための高級ライブラリ、Task Regionの提案。前回の論文、N3832からの変更点としては、task_regionから発生した子タスクと明示的に通信するためのtask_region_handle。

N3992: Agenda and Meeting Notice for WG21 Telecon Meeting

6月6日に開催された電話会議の予定表

[まだPDFだ] N3993: On Parallel Invocations of Functions in Parallelism TS

現在TSに提案されている、<algorithm>に実行ポリシーによるタグディスパッチを追加して、並列実行やベクトル実行が出来るようにしようという提案の文面案で、ソートはswapを並列に呼び出すが、要素がオーバーラップしない時だけに限るという保証を与えるために、Hans Boehmが文面案を改正すべきだという意見を出したので、それに伴い、文面案を変更する提案論文。

N3994: Range-Based For-Loops: The Next Generation (Revision 1)

range-based for loopで、for ( elem : range ) を、for ( auto && elem : range )にするための軽いシンタックスシュガーの提案。

N3995: A proposal to add shared_mutex (untimed) (Revision 2)

C++11でshared_mutexと呼ばれていたものは、TimeLockable要件(try_lock_for/try_lock_until)を満たすので、実はshared_time_mutexと呼ぶべきであったので、そのように改名する提案が可決された。そこで、TimeLocakble要件を満たさない、本当のshared_mutexを追加する提案。

[長大なPDF] N3996: Static reflection

130ページもある長大なPDFの論文。

静的リフレクションに関する論文。

例えば、クラスの内部状態をバイナリとかXMLとかJSONなどといった何らかのフォーマットに書き出したり、そのフォーマットから読み込んでクラスの内部状態を再現したりしたいとする。これは一般に、Serializationと呼ばれている。serializationを実装するには、クラスの意味のあるデータメンバーをそれぞれ読み書きする必要がある。これを手動であらゆるクラスに対して手で書くのは面倒である。極めて単調で、機会的に生成できるコードである。何か、クラスのデータメンバーをコンパイル時に列挙して、それを元にコンパイル時にコードを生成するような機能があればいいのだが。

その機能を提供するのが、リフレクション(Reflection)だ。リフレクションによるリフレクティブプログラミング、これはメタプログラミングの一種である。そのリフレクションをコンパイル時に行うので、静的リフレクションとなる。

論文は、静的リフレクションで取得可能なコード情報や、Technical Specification文面案など、やたらと大量の文章を含むので、ここまで膨れ上がった。

[PDFから身を守りたい] N3997: Centralized Defensive-Programming Support for Narrow Contracts (Revision 5)

防衛的プログラミングと称して、高機能assertマクロをライブラリとして追加する提案。

筆者はCプリプロセッサーを使う提案に反対の立場である。

N3998: C++ Latches and Barriers

ラッチとバリアーというライブラリの提案。

ラッチというのは、ひとつ以上のスレッドをブロックしておくためのライブラリである。ラッチは初期化時にカウントを指定する。latch::arrive()を呼び出すことで、カウンターがデクリメントされる。カウンターがゼロに達すると、latch::wait()を呼び出すことでブロックされていたスレッドが実行を再開する。


// ラッチオブジェクト
// カウンターは3
std::latch l( 3 ) ;


// (複数の)スレッド
void waiting_thread()
{
    // 処理がすべて終わるまで待機
    l.wait() ;
}

// 処理、三回呼ばれたらラッチによるブロックが解除される。
void operation()
{
    l.arrive() ;
}

ラッチは、一度きりしか使えず、再利用できない。

バリアーは、再利用できるラッチである。

さらに、notifying_barrierというクラスもあり、これは、終了条件に達した時点で、設定した関数が呼ばれるものである。

それにしても、どうも名前が聞きなれなくてややこしいと思うのは筆者だけだろうか。とくに、スレッド間の同期でいえば、ずぼらな人のためのアトミック操作であるメモリバリアーとややこしいと思うのだが。

[またPDF] N3999: Standard Wording for Transactional Memory Support for C++

トランザクショナルメモリーの文面案。前回からの変更は小粒。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今日、社内で謎のダンスが流行っていた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0