2016-02-11

Warner Music、ハッピーバースデーの歌の著作権を保有していないことを認めて訴訟を降りる

Warner Music Pays $14 Million to End 'Happy Birthday' Copyright Lawsuit - Hollywood Reporter

アメリカ合衆国で、有名なハッピーバースデーの歌(Happy Birthday To You)の歌の著作権使用料を請求していたWarner Musicに対し、同歌の歴史ドキュメンタリーを作成していた映画監督のJennifer Nelsonが、Warner Musicは著作権を有していないとしてクラスアクション訴訟を起こした。

この訴訟では、Warner Musicの提出した、著作権の委託管理を受けたという証拠となる出版物の肝心な部分が画像がやたらボケているので、現物を入手してみたところ、ボケた部分にはWarner Musicの主張するような記述がなかったという証拠まで提出されている。

2016-02-06

最近遊んだ不自由なビデオゲーム

不自由なゲーム専用OSであるWindows箱で最近遊んだゲームを紹介する。

Keep Talking and Nobody Explodes

爆弾解体ゲーム。ビデオゲームというよりはボードゲームに違い。ビデオゲーム側としては、爆弾を解体する操作を提供している。このゲームを遊ぶには最低二人が必要である。一人がコンピューターを操作して爆弾を解体する。爆弾を解体する人は、爆弾の解除マニュアルを読むことができない。

残りのプレイヤーは、できれば紙に印刷された爆弾解除マニュアルを読む。そして、爆弾を解体する人間と、口頭で通信して爆弾を解除させる。

爆弾解除マニュアルは不必要に回りくどく書かれている。そのため、爆弾解除係とマニュアル読者は不毛なやり取りを繰り返すことになる。例えば、以下は典型的なプレイ中の会話である。

マニュアル係「どんなモジュールがある?」
解体係「えーと、何か線がいっぱいあるやつがある」
マニュアル係「線は横? 縦?」
解体係「横」
マニュアル係「線は何本?」
解体係「5本」
マニュアル係「えーと、最後の線は黒い」
解体係「えーと、線は上から白、赤、黄色、赤、黒」
マニュアル係「最後の線の色は?」
解体係「黒」
マニュアル係「えーと、箱のどこかにシリアルナンバーがあるはずなのだけど」
解体係「シリアルナンバー?」 マニュアル係「そのシリアルナンバーの最後の桁は奇数?」
解体係「シリアルナンバー・・・あ、あった、でなんだっけ?」
マニュアル係「そのシリアルナンバーの、えーと、最後の桁は奇数」
解体係「最後の桁は・・・4」
マニュアル係「4は・・・偶数なので奇数じゃないか。次行って・・・赤い線はある?」
解体係「ある」
マニュアル係「何本ある?」
解体係「2本」
マニュアル係「えーと、じゃこれも違って・・・黒い線はある?」
解体係「ある」
マニュアル係「ということは・・・えーと、最初の線を切って」

これはとても面白い。

BioShock Infinite

待望のBioShockシリーズの第三段。だが期待されすぎた凡作。

グラフィックと音楽はいいのだが、戦闘が極めて退屈で、ストーリーも大して面白くない。エリザベスも可愛くない。

Kerbal Space Program

宇宙開発をするゲーム。ロケットを組み立てて地上から発射し、軌道に載せ、惑星探索をするゲーム。

舞台は地球のような恒星系を持つ惑星Kerbinから始まる。Kerbinは地球の10分の1のサイズなのに表面重力は同じというとても密度の高い物質で構成されている。

とても面白くて中毒性のあるゲームだが、筆者はまだ軌道にすらのせることができていない。軌道は極めて常識に反する。

Grapple

粘性のある球体がGrappling hookを駆使しながらスタートからゴールに移動するだけの面クリア型ゲーム。とても単純だがとても面白い。

Tower of Guns

ランダム生成されるステージ群をクリアしていくFPS。極めて単純だが面白く、息抜きに良い。

2016-02-05

往年のDOSマルウェアをDOSエミューレーター上で実行できる博物館

電子データの収集保存活動をしているInternet Archive(archive.org)が、1980年台、1990年台に流行した秀逸な画面効果を持つDOSマルウェアをブラウザー上でエミュレーターDOSBoxを使い安全に実行可能な状態で展示している。

The Malware Museum : Free Software : Download & Streaming : Internet Archive

とても興味深い。

2016-02-01

Archユーザー、rm -rfしてMSIのラップトップのUEFIのバグを発見する

No POST after rm -rf / / Kernel & Hardware / Arch Linux Forums

No POST after rm -rf / | Hacker News

Mount efivarfs read-only · Issue #2402 · systemd/systemd

Archのインストールを消去したかったので、遊びのためにMSIのラップトップで"rm -rf --no-preserve-root /"してみたArchユーザーのラップトップが文鎮化してしまった。なぜだ。

調査の結果、おそらく/sys/firmware/efi/経由でEFI変数(EFIの規格で定められているマザーボードが提供する小容量の不揮発ストレージ)に書き込みを行ったためだと判明した。

EFI変数に書き込むのは、EFI規格上完全に合法な操作であるが、どうやらファームウェアの不具合で、このMSIのラップトップでEFI変数に書き込むと文鎮化してしまう不具合があるらしい。

3年前にも似たようなことが話題になっていた。本当にEFIの現実の実装はクソだ。

本の虫: UEFIとLinuxの現状

もはやここまで現実の実装がクソであると、EFI規格は脆弱性を発生させるために国家の諜報機関によって意図的に複雑にされていることを疑いたくなる。

2016-01-31

闘会議2016のアナログゲームのとある運営スタッフの感想

闘会議2016のアナログゲームのインスト要員として2日間運営スタッフとして入っていたので、その感想を書く。

筆者は江添亮、ドワンゴにエンジニアとして雇われている。ドワンゴのボードゲーム同好会のメンバーでもある。今年の闘会議でも、アナログゲームは設置される。もちろんカタンもある。カタンのインストをするために運営スタッフとして参加した。

今回の闘会議には不安が大きかった。なにしろ、今回のアナログゲームエリアには、30卓ほど立てるという予定である。1卓にスタッフを2人配置するとして、60人必要になる計算だ。60人ものボドゲがインストできるスタッフをどこから集めてくるというのか。あまりにも無謀すぎる。私が一切関わっていない会社の企画するイベントが失敗するのは私の知ったことではないが、カタンのインストが失敗し、カタンに悪い印象を与える事態だけは、ガチのカタンプレイヤーとして見過ごすことはできぬ。そこで、カタンのインストのために運営スタッフとして参加した。

今回の闘会議では、ドワンゴのエンジニアには動員がかからなかったので、社内からはボドゲをインストできるスタッフがせいぜい5,6人程度しか出なかった。60人ものインスト要員をどうやってまかなうつもりなのだろうか。

私「そもそも必要なだけの頭数はいるのか?」
企画「5,60人ほどいます」
私「そのうちボドゲ経験があってインストができる人は?」
企画「3分の1ぐらい・・・コネで集めました」
私「残りは?」
企画「派遣バイトです」

嫌な予感しかしない。

ボードゲームの上手なインストは、ある程度のボードゲーム経験とインスト経験を必要とする。経験が全てではないが、最低限のボードゲーム慣れ、場慣れする必要がある。派遣バイトの中にボードゲーム経験のある人間がどのくらいいるだろうか。第一、どうやって募集しているのだ。「闘会議、アナログゲームエリアでボードゲームの解説と、場合によってはプレイヤーとしても参加して場を盛り上げてもらうお仕事です!」といった具体的な告知があれば、まだボードゲーム経験のある人間や、説明慣れしている人間が集まりやすそうではある。しかし、もし単なる「闘会議イベントの運営スタッフです!」程度の告知であったならば、イベントの運営スタッフ慣れしている人は応募するだろうが、ボードゲーム経験は望めそうにもない。

「で、バイトは前日のリハーサルに来るの?」
企画「全員来ます」
「すると前日のリハーサルで我々がバイトにインストして、翌日にインストしてもらうのか」
企画「そうです」

大丈夫なのだろうか。初対面の人間に複雑なルールの説明をする作業というのは、人によっては不得意な作業である。思うに、必要なのは少しの経験による場慣れだと思うのだが、今回は、その少しの経験を詰むほどの時間もない。

そして極めて絶望的なことに、この会話が行われたのは、闘会議までもう数えるほどしか日数がない時点である。根本的にスケジュールがおかしい。

そして前日リハーサル。私は今年木場に引っ越したので、闘会議の会場である幕張メッセのある海浜幕張までは、だいぶ近くなった。東西線で西船橋まで行き、JRに乗り換えて、武蔵野線で南船橋に行き、京葉線で海浜幕張に行く。タイミングが良ければ、西船橋から直通運転で一本で海浜幕張まで行けることもある。

私は予定通り西船橋で降りて乗り換えた。そして南船橋まで着いたが、何故か電車がホームに止まったまま、なかなか発車しない。しばらく待った結果、とうとう発射したが、なんともと来た線路を戻っていくではないか。しまった。これは南船橋が終点で西船橋に折り返しているのだ。こうして、予定より遅れて会場に到着した。

さて、肝心の派遣バイトだが、やはりボドゲ経験のある人は皆無であった。ボードゲームによっては、日本語の説明書が付属していないものまである。ボドゲのインストを始めるが、やはり完全にボドゲ未経験では、マニュアル読み上げのような説明になってしまいわかりづらい。

カタンは、私の他にもう一人、カタンを5,6回ぐらいプレイしたことがある人間がインストをするようだ。カタンは最低100回ぐらいはやらないと感覚がつかめない。

さて闘会議1日目の朝、私は正しい電車の乗り換えに成功して会場に着いた。小雨が振っており極めて寒い。異様なほどに寒い。ここまで寒いと客足が遠のくのではないかと思われるぐらい寒い。幕張メッセの中は、強力な暖房に温かいのだが、外は死ぬほど寒い。

開場して人がなだれ込んでくる・・・かと思いきや、それほどの人数ではない。やはり天候が客足に影響を与えているのだろうか。それとも、今回は借りているホールが多いので、相対的に人が少なくみえるのだろうか。

去年に引き続き、麻雀は人気だ。すぐに卓が成立する。ボドゲの成立には少し待たねばならない。程なくしてボドゲ卓も埋まった。

カタンのルールをすべて口頭で説明すると30分ほどかかる。それに、口頭で説明されたことをすべて覚えられるわけがない。そこで、基本的なルールだけ教えて、後はプレイしながら教えていく方法を取った。これならば最初の何もしない状態での説明は5分か10分ほどですむ。

また、今回のカタンのインストを通じて、カタンでは初期配置が非常に重要だという認識を新たにした。ダイスの確率の説明は最初に行っているのだが、やはりカタンは数百回ほどやらないと感覚がつかめないのか、初心者は確率の極めて悪い場所に初期配置しようとする。去年の闘会議では、極端に確率が悪い場所に設置したものだけ助言をしていた。その結果、プレイヤーによって初期配置に極端な差が生まれ、トップを妨害する暇もなく30分ほどでゲームが終了してしまうことがたまに見られた。

今回は、何百回もカタンを対戦している筆者の感覚で、確率、資源バランス、港、目かぶり、他プレイヤーの影響まで含めた初期配置を強力に助言した。その結果、なんと初心者が4人集まった卓であっても、中盤から終盤にかけてのトップ阻止のどんでん返しが何度も起き、ガチ勢が経験するものと同じ極めて熱い戦いになった。

なるほど、カタンは初期配置が極めて重要なのだ。一人でも初期配置が悪いプレイヤーがいると、あるプレイヤーが極端に有利になりすぎてバランスが崩れ、張り合いのないプレイに成り下がってしまう。1番手、2番手に本来残るはずのない良い2件目の建設場所を与えてしまったり、3番手4番手に本来残るはずのない1件目の建設場所を与えてしまったりする。

ちなみに、一回だけ、カタンを所有していて家でよく遊んでいると主張する母と息子の親子2人で参加しておきながら、筆者の助言を聞かず、「置きたいところに置けばいいじゃない」とつぶやきながら、親子揃って悪い配置をした親子がいたが、親子揃って終盤まで全く伸びずに勝ち目がなかった。プレイ中の建設戦略も極めて悪く、序盤から意味もなくThe Longest Roadだけを狙って無駄な建設したりしていた。The Longest RoadとThe Largest Armyは補助的な点数であって、序盤から無理に狙いに行くものではないのだが、この辺の感覚は、強いプレイヤーと数百回の対戦をしないとわからない。カタンを所有していてよく遊んでいるとはいえ、適切な上達者の指導がなく、弱い初心者同士が狭い世界で戦っていると、こういう袋小路に陥る。大抵のゲームにありがちの問題だ。

さて、小学生ぐらいの子供が卓に着いた。子供にカタンのルールを教えるのは難しい。カタンはそれほど難しいゲームではないが、6面ダイスを2つ振った出目の合計値の確率から、戦略や得点方法まで、様々な馴染のない要素を理解させなければならない。将棋やチェスのような有名なボードゲームならば、戦略書がすでに山ほど出ていて、ある程度まで強くなるには、先人が考えぬいた結果の定石の暗記とパターンマッチだけですむのだが、カタンなどのボードゲームの場合、ルールをその場で聞いて理解し、自分で与えられたルールの範囲内で柔軟に戦略を考えなければならない。ただし、筆者の経験では、闘会議のアナログゲームの上級エリアにわざわざ来るぐらいの子供は、そういう処理も得意であるようだ。この子はどうだろう。

筆者「カタンはやったことあるかな?」
子供「はい、去年の闘会議ではじめてやりました」
筆者「何、ひょっとして私がインストした?」
子供「はい、そうです」

なんと、去年私がカタンを教えた子供が今年もやってきてカタンをするというのか。

うおおおおおおおお!!!!! 自分は今猛烈に感動している。

しかも、去年より遥かにうまくなっているし、結果として勝利したではないか。圧倒的にいい話だ。

1日目の最後は、人が集まらなかったので筆者もプレイヤーとして参加した卓で、閉場までの時間が残り僅かしかない状態で猛烈なトップへの妨害と勝利争いになり、最終的に筆者が勝利した。このゲームは極めて劣悪な盤面で、鉄が固まっているが、8鉄以外は確率が悪く、麦が不作であった。筆者は8土と土港を序盤で確保して、勝利を確信したのだが、当然残りの3人の注意を惹きつけてしまい、序盤の盗賊の標的にされた上に、中盤では8が全く振られることがなかった。終盤でトップの勝ちを阻止するためにThe Longest Roadの激しい奪い合いになり、また終盤の最後で、これまでの不足分を取り返すかのように8が出始めて巻き返し、中盤は盗賊と8が振られないことにより完全に死んでいたことから妨害の注意がそれていたために勝利した。

こうして闘会議の1日目が終わり、寒さに震えながら帰路についた。帰り道が同じであった自転車好きの同僚と自転車について話をしていて、自宅から職場まで5kmなので、十分に自転車通勤が可能な距離であるが、自転車を買う決心がつかないため、いまだに自転車通勤できていないことを話すと、「ぜひ自転車通勤するべきだ。まずは安い20万ぐらいの自転車を買って始めるといい」と言われた。自転車に20万も出すとは。しかもそれが安いだと。住んでいる世界が違う。ゲームPCの値段であれば安いのだが。

帰路、海浜幕張から南船橋で乗り換えようとして、別のホームに向かってしまい、発射直前の列車にろくに確認もせず飛び乗った結果、海浜幕張に逆戻りしてしまった。また、帰りの電車で傘をなくしてしまった。

闘会議2日目

朝に木場から海浜幕張に向かう。西船橋で乗り換えをして乗った電車は、何か違和感がある。行き先を見ると市川塩浜駅となっている。これは逆方向だ。南無三、また間違えたか。市川塩浜駅で降りて、逆方向の列車に乗ることで、海浜幕張まで一本で到着した。

2日目も1日目と同様にカタンのインストをした。帰りの電車は間違えなかった。

去年の感想。

本の虫: 闘会議2015のアナログゲームエリア、とある運営スタッフの感想

ドワンゴ広告

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

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

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

2016-01-24

グラビティリサーチ銀座に行ってきた

銀座に最近できた新しいクライミングジムのグラビティリサーチ銀座に行ってきた。

GRAVITY RESEARCH 銀座 | クライミング(ボルダリング・スポーツクライミング)ジム グラビティ リサーチ GRAVITY RESEARCH

このクライミングジムの最大の特徴は、銀座にあるということだ。職場が銀座の場合、仕事上がりに登るのに最適だ。

入会金が1500円で、21時以降の料金が1600円。他のジムと比較すると深夜料金が高い気がするが、これは税込み料金であることと、銀座にあるということと、職場が銀座で平日の仕事上がりに他のジムに行く場合、交通費が別にかかるということを考えると、こんなものかもしれない。

ジムの中はそれほど広くはないが、壁の横幅と課題の数はそれなりにあった。ただし天井が低い。

課題はグレードに対して簡単であるように感じた。

職場から歩いていける距離にあるという店で、グラビティリサーチ銀座は価値のあるジムだ。もし午前中からやっているのであれば、朝ボルダリングが可能だったのだが、残念ながら、14:30から開店する。

定期会員になって、平日毎日30分ぐらいの短時間利用するのは悪くなさそうだが、残念ながら3ヶ月単位でしか定期購入できない。一ヶ月ならばその月は集中して登るのもありなのだが、さてどうしよう。

ところで、このジムにはドワンゴのボルダリング同好会として同僚3人で行ったのだが、宛名「ドワンゴ ボルダリング同好会」で領収書を書いてもらったところ、「ボルダリング同好会って何をするんですか?」と聞かれた。はて、ボルダリング同好会を名乗る団体がクライミングジムに来ている。これ以上に自明なことがあるだろうか。

第2回 ドワンゴからの挑戦状の予選に参加した

第二回、ドワンゴからの挑戦状の予選に参加した。公式Webサイトは以下の通り。

第2回 ドワンゴからの挑戦状 | 株式会社ドワンゴ

もう予選は終わってしまったが、問題は今からでも挑戦することができる。問題に挑戦するには以下のWebサイト上から行う。

Welcome to 第2回 ドワンゴからの挑戦状 予選 - 第2回 ドワンゴからの挑戦状 予選 | AtCoder

これは高橋直大さんの会社、AtCoder社の運営する競技プログラミングのWebサイトで、今回の競技プログラミングのジャッジシステムと問題作成のためにAtCoder社に協力してもらっている。

問題は、A, B, C, D, Eの5問あり、それぞれに点数が設定されている。CDE問題には、部分点も設定されてる。

回答をするには、問題とプログラミング言語を選び、ソースコードを貼り付けて提出すると、atcoderのサーバー側でコンパイルとテストケースに対する実行が行われて、結果がみられる。問題を解くためには、まずソースコードのコンパイルやパースに失敗しないこと、正しい回答を出力すること、実行時間、メモリ使用量が制限以内であることが求められる。

この予選の上位入賞者は、2月13日にドワンゴ本社で行われる本選に参加できる。本選での上位入賞者には賞金が出るほか、2017年度新卒である場合、ドワンゴへの新卒採用における一部の面接をパスできる。

去年行われた際、筆者は予選終了後に問題を解いたが、今回はリアルタイムで予選に参加した。筆者は競技プログラミングは得意ではないが、難易度が去年と同じ程度である場合、仮にもドワンゴでエンジニアという役職で雇用されている以上、B問題ぐらいまでは解けなければ沽券に関わる。

A: ニコニコ数

問題分だけ抜粋すると、以下の通り。

ニコニコ数とは、10進法で表記したときに 2 と 5 が交互にあらわれ、かつ一番上の位が 2 で一番下の位が 5 であるものです。 例えば、 25,2525,252525252525252525 などはニコニコ数であり、 467,5252,5 などはニコニコ数ではありません。

ニワンゴくんは、 N 以下の正の整数のうち、約数にニコニコ数を持つものがいくつあるかを調べようと思いました。ニワンゴくんに代わって、この問題を解くプログラムを作ってください。

筆者はこの問題を以下のように読み間違えてしまった。

ニワンゴくんは、 N 以下の正の整数それぞれについて、すべての約数のうちニコニコ数である数字の合計値がいくつあるかを調べようと思いました。

つまり、筆者の誤った解釈では、2525はニコニコ数となる約数として25と2525を持つので、出力すべき数字の合計値に2を足すべきだとなる。そのため、2525を超える値について、出力が間違ってしまった。そして、解釈間違いに気がつくまでに、実に不毛な考察が行われた。結果が32bit符号付き整数に収まらないのではないか。いや、Nは10の9乗以下であるので問題はない。どこかにコンパイルエラーにならないタイプミスがあるのか。などなど。

さて、正しい解釈でこの問題を考えると、ニコニコ数2525は約数として25を含むし、252525も約数として25を含む。したがって、約数として25が含まれるかどうかのみを考えればよい。約数の25が含まれる値は25の倍数であるし、単純にNを25で割ればよい。

#include <iostream>
 
int main()
{
    unsigned N{} ;
    std::cin >> N ;
    std::cout << N /25 << std::endl ;
}

B: 積み鉛筆

問題分はリンク先を参照してもらうとして、A問題に時間をほとんど使い尽くしてしまったので、B問題を解く時間が30分ぐらいしか残されてない。

さて、これは一体どうすればいいのだろうか。整合性を保つために手直しをすると、前の鉛筆まで手直しが発生するのではないか。するとバックトラック的な何かをする必要があるのだろうか。

ぼんやりと鉛筆を詰んでいる図の例をながめていると、ふとひらめいた。

2本の上段の鉛筆KiとKi+1に対して、下段の整合性を保つ必要のある鉛筆は、LiとLi+1とLi+2の3本だけだ。Li+2の長さをKi+1とKi+2の都合で変えても、Liを整合性を保つために変更する必要はない。そして、整合性を保つ方法というのも、KiとKi+1の長さを、Li+1とLi+2に入れて、それで整合性が取れなければ、LiとLi+1に入れるだけでいいのではないか。2つの連続した鉛筆Kに対しては、その下の3本の鉛筆Lしか考慮しなくてよい。

さっそくそのようなコードを書き、投稿。なぜかWA(Wrong Answer)とTLE(Time Limit Exceeded)の嵐。何がまずいのか。入力をすべてメモリ上に読み込んでいるからまずいのか。そんなことをせずに逐次に処理をしていくべきなのか。いや、入力は10の5乗程度でしかなく、TLEを起こすはずがない。WAはなぜだ。少なくとも問題の入力例に対しては正しい答えを出せているのだが。

そしてここで時間切れとなった。時間切れ後に気がついたのだが、どうやらB問題の回答をA問題に対して提出していたようだ。B問題に対してそのまま提出すると、普通に通った。なんということだ。

実質B問題まではできたと言えるので、最低限の沽券を守ることはできた。

C: メンテナンス明け

残念ながら、私はC問題以降を解説するだけのアルゴリズム力を持たない。しかし、C問題についてはいろいろと面白い裏話を聞いている。

この問題は、ドワンゴ社内でtayamaというハンドルネームを用いているドワンゴ社員によって作成された。

問題を作成してAtCoderに提出したところ、AtCoderの高橋直大社長から、「何のひねりもない問題」と言われたそうだ。tayamaさんはこれを、「アルハラ(=アルゴリズム・ハラスメント)である」とコメントしている。

また、この問題は、本来D問題にする予定で作ったのだが、直大社長に、「簡単じゃない?」と言われたためC問題になったのだという。

また、この問題には入力の大小に応じて、SmallとLargeというテストケースが用意されており、それぞれに点数が設定されている。テストケースが弱く、Smallには通らないのにLargeに通るコードが書けてしまうそうだ。

また、テストケースに、"small/91_tayama_killer_00"という名前のテストがあるが、これは問題作成者であるtayamaさんの当初書いた回答コードに通らない例が発見されたために追加されたテストケースだそうだ。

さて、本選は2月13日にドワンゴ本社で行われる。

ドワンゴ広告

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

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

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

2016-01-20

C++標準化委員会の文書のレビュー: P0160R0-P0172R0

P0160R0: Wording for removing defaults for unary folds

fold式からデフォルト値を削除する文面案。

P0162R0: A response to "P0055R0: On Interactions Between Coroutines and Networking Library"

「現在提案中のBoost.Asioベースのネットワークライブラリの状態保持のための動的ストレージは、コルーチンのスタック上に確保すれば高速になるので、規格でそのように規程すべきだ」という提案に対し、「そのような設計は実装の自由度を制限してしまい好ましくない。同等の高速化はBoost.Asioのカスタムアロケーターでも可能で、最近のAsioはデフォルトのアロケーターを使った場合でも最適化を自動的にするようになっているので、規格でもそのように規定しよう」という反論。

P0163R0: shared_ptr::weak_type

shared_ptr<T>に対応するweak_ptr<T>のネストされた型名、weak_typeを追加する提案

shared_ptrからweak_ptrを作るには、weak_ptrの型を具体的に記述する必要があった。これではジェネリックなコードを書きにくいので、N4537ではshared_ptrに対応するweak_ptrを返すunlockというメンバー関数を追加する提案をしたが、これは却下された。

しかし、やはりweak_ptrの型を直接書くのは嫌なので、今度はshared_ptrに対応するweak_ptr型のweak_typeというネストされた型名を追加する。

つまり、以下のようなコードを解決する。

template < typename T >
void f( T & t )
{
    auto sptr = t.get_shared_ptr() ; // 何らかのshared_ptrが返される
    std::weak_ptr<???> wptr = sptr ; // 型がわからない。
}

この問題を解決するために、従来、以下のようなコードが書かれてきた。

template < typename T >
std::weak_ptr<T> unlock( std::shared_ptr<T> const & sptr )
{
    return std::weak_ptr<T>( stpr ) ;
}

template < typename T >
void f( T & t )
{
    auto sptr = t.get_shared_ptr() ; // 何らかのshared_ptrが返される
    auto wptr = unlock(sptr) ;
}

この提案を使えば、以下のように書ける。

template < typename T >
void f( T & t )
{
    auto sptr = t.get_shared_ptr() ; // 何らかのshared_ptrが返される
    auto wptr = typename decltype(sptr)::weak_type(sptr) ;
}

unlockの方がわかりやすい気がするのだが。

P0164R0: Core Motions

Core issuesに対する解決の中で規格入りする準備ができたもの一覧

P0165C++ Standard Library Issues to be moved in Kona

Library issuesに対する解決の中で規格入りする準備ができたもの一覧

P0166R0: Three interesting questions about contracts

関数にprecondition, postcondition, invariantを記述できるcontract機能を使って、どのようにvectorのようなクラスで範囲外チェックを記述できるのかというHerb Sutterの提示した問いに答える文書。

P0167R0: Core "ready" Issues

2015 Kona会議以降に規格入りする準備が整ったcore issueの解決の一覧。

P0169R0: regex with Unicode character types

regexをUnicode(char16_t, char32_t)に対応させるために必要な設計の考察。

char32_tはUnicodeコードポイントをほぼそのまま表現できる。basic_regex<char32_t>を実現するには、<locale>をchar32_tに対応させる必要がある。具体的には、ctype<char32_t>, collate<char32_t>, collate_byname<char32_t>を実装する必要がある。

char16_tの方は、char32_tのように実装さえすれば動くわけではない。UTF-16にはサロゲートペアが存在するので、char16_tの一つのオブジェクトは1文字を表現しない場合がある。しかし.(dot atom)とか\S(predefined character class)はサロゲートペアの片割れにマッチしてしまう。サロゲートペアがあるため、char16_tは<locale>をサポートできない。

UTF-16ではなく、UCS-2(サロゲートペアのない16bit固定長Unicode符号。BMPだけをサポートしたもの)をサポートするという案は採用できない。なぜならば、UCS-2はすでにISO/IEC 10646においてdeprecated扱いされているため、今から発行する規格がUCS-2だけをサポートするというのはありえない。

ではどうするのか。basic_regex<char16_t>は提供せず、char16_tとchar32_tを相互変換するイテレーターを提供するという案がある。

他には、char16_tは、現行のbasic_regex<char>と同じく、可変長エンコードをそのまま突っ込んだものとみなし、特に何も対応せずそのまま提供するという案もある。この案を採用する場合、Unicodeに関してはchar32_tに変換した上でbasic_regex<char32_t>を使うべきだ。

筆者の意見では、UTF-8, UTF-16, UTF-32を簡単に変換できる関数と、相互に通過的に変換するイテレーターを提供した上で、正規表現を使いたければbasic_regex<char32_t>に一本化する方法がいいと思う。

P0170R0: Wording for Constexpr Lambda

constexpr lambda式の文面案。

auto f = []( int x ) { return x ; } ;
constexpr int i = f(0) ; // OK

P0171: Response To: Resumable Expressions P0114R0

Resumable Expressionに対して寄せられた懸念事項に答える文書。

言語規格がスケジューリングまで定めるべきではないという意見に対しては、提案しているのはシンタックスシュガーだけで、スケジューリングの詳細はライブラリが実装すると回答。

resumable関数を呼び出す際にawaitを書き忘れると、実に不具合箇所を特定しにくい不具合の元になるという意見に対しては、現在提案中の戻り地を無視すると警告する[[nodiscard]]のような属性を提案すればよいと回答。

P0172R0: Abominable Function Types

C++の型システムには、コンパイラー開発者とメタプログラマーしか知らない闇がある。Abominable functionと名付けられた型のことだ。

abominable functionとは、CV修飾やリファレンス修飾された関数型のことだ。

using regular = void () ;
using abominable = void () const volatile && ;

非メンバー関数はCV修飾やリファレンス修飾することはできない。しかし、関数型はCV修飾、リファレンス修飾ができてしまう。

このようなabominable function型は、ほとんど利用価値がないが、traitsを実装する際に個別に対応しなければならないため、問題になる。

このAbominable functionをどうにかしようと問題提起する文書。

ドワンゴ広告

1月23日にはドワンゴ主催のプログラミングコンテストが行われる。

第2回 ドワンゴからの挑戦状 | 株式会社ドワンゴ

前回と同じく、競技プログラミングの環境にはあのAtCoder(株)の社長であり最強最速アルゴリズマー養成講座の著者でもある高橋直大氏のAtCoder (アットコーダー)を利用している。

このコンテストの予選を突破し、2月13日の本選の上位入賞者の2017年新卒には、採用試験の一部免除などの特典があるそうだ。

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

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

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

2016-01-18

C++標準化委員会の文書のレビュー: P0144R0-P0159R0

P0144R1: Structured Bindings

多値を返す関数の戻り値を簡単に変数に束縛できるようにするための文法の提案。

現在、C++ではtupleがあるために、多値を返す関数を簡単に宣言することができ、また簡単に多値を返すことができる。

std::tuple< T1, T2, T3 > f( )
{
    T1 a{} ; T2 b {} ; T3 c { }
    return { a, b, c } ;
}

見ればわかる通り、極めて簡単だ。

呼び出し側で多値を受け取るのも、比較的簡単である。

T1 a ; T2 b ; T3 c ;
std::tie( a, b, c ) = f() ;

確かに、比較的簡単ではあるが、このコードはいろいろと問題がある。

変数をあらかじめ宣言しなければならない。もし、型がPOD型ならば、未初期化の状態となり、お作法上あまりよろしくない。

型がクラス型の場合、デフォルト構築が行われる。その直後にコピー/ムーブして上書きするのに、デフォルト構築するのは無駄だ。

そこで、複数の変数の宣言と、その変数群を多値のそれぞれの値で初期化する新しい文法を追加する提案。

現在、以下の文法が提案されている。

auto { a, b, c } = f() ;

この宣言文は、変数、a, b, cを宣言する。変数の型はそれぞれ独立して初期化子から推定される。

この提案では、以下の2つの新しい文法を提案している。

auto { list-of-comma-separated-variable-names } { expression };
auto { list-of-comma-separated-variable-names } = expression;

expressionは、tupleとpairの場合、それぞれの要素で型推定され、初期化される。式は変数と同じ個数の要素をもたなければならない。

std::pair< T1, T2 > p{ ... } ;
auto { a, b } = p ;

std::tuple< T1, T2, T3 > t{ ... } ;
auto { x, y, z } = t ;

式には、クラス型を指定することもできる。このときクラス型のすべての非staticデータメンバーはアクセス可能で、ひとつの基本型(そのクラス型も含む)で宣言されていなければならない。

struct X { int a ; double b ; } ;

X x{ 0, 0.0 } ;

// aはint、bはdouble
auto { a, b } = x ;

クラスが無名unionメンバーを含む場合、最初のメンバーが選ばれる。


struct X
{
    union { int i ; double d ;} ;
    int data ;
} ;

X x{ {0}, 0 } ;

// xはint型で値は0
auto { x, y } = x ;

autoにCV修飾子やlvalueリファレンス修飾子を使うこともできる。

auto const { x, y, z } = f() ;
auto const & { x, y, z } = f() ;

rvalueリファレンス修飾子のサポートについては、議論中。

この文法は、initializer_listからの初期化はサポートしない。

braced-init-listからの初期化もサポートしない。

// サポートしない
auto { x, y, z } = { 1, 2, 3 } ;

理由は、この文法を追加するのは簡単であるが、この文法の有益な利用例がいまのところないため。

再帰的な構造化解除はサポートしない。

std::tuple< T1, std::tuple< T2, T3>, T4 > f() ;

// サポートしない
auto { a, {b, c}, d } = f() ; 

将来の拡張案としては興味深い。

[PDF] P0145R0: Expression Order of Evaluation

式のオペランドの評価順序を固定する提案。

たとえば、f( a, b, c )という式があるとき、オペランドf, a, b, cがどの順番で評価されるのかは、規格上は未規定(unspecified)とされていた。そのため、シークエンスポイントを隔てることなく、2つのオペランド中の式が同じオブジェクトを変更するとき、挙動は未定義となる。例えば、f( i++, i )のような式で、iが整数型の変数の場合、挙動は未定義となる。v[i] = i++も同じだ。

f( i++, i )やv[i] = i++のような昔からよく知られた問題ばかりではない。例えば、以下のようなコードの挙動も未規定だ。


#include <map>

int main()
{
    std::map< int, int > m ;
    m[0] = m.size() ; // #1
}

#1が評価された後のmapの中身はどうなっているだろうか。{{0,0}}だろうか、{{0,1}}だろうか。規格上は未規定だ。

式の評価順序が未規定という問題は、単にプログラマーの娯楽とか、採用試験とか、学術的な興味にとどまる問題ではない。現在の規格の制約は、現実の日常的なプログラミングに問題を引き起こしている。例えば以下のコードだ。

void f()
{
    std::string s = “but I have heard it works even if you don’t believe in it”
    s.replace(0, 4, “”).replace(s.find(“even”), 4, “only”).replace(s.find(“ don’t”), 6, “”);
    assert(s == “I have heard it works only if you believe in it”);
}

s.replace(...).replace(...).replace(...)と、いわゆる"method chaining"的なメンバー関数呼び出しの仕方をしている。これらがすべて、ひとつの式の中のサブ式であるので、その評価順序は未規定である。評価順序が未定義な以上、assertは引っかかる可能性がある。findの後に、そのfindを含まない別のreplaceが評価されるとassertに引っかかる。

このコードの問題点は、極最近になってツールで検証した結果明らかになった。

このコードは、Bjarne StroustrupのThe Programming Langauge 4thに載っているコードであり、この本は世界屈指のC++専門家達によって査読されていた。そのような環境ですらこの問題が発覚しなかったということは、現在の規程に問題がある。

このようなメソッドチェイニングが問題なのだとする批判は当たらない。なぜならば、std::cout << e1 << e2 << e3のような式も影響を受けるし、std::future<T>はメソッドチェイニングを前提としたthen()メンバー関数を追加する予定である。問題はメソッドチェイニングではない。

しかし、評価順序の未規定ルールは、何十年も存在する。なぜ今変えるのか。当時の制約ある環境では、この規程は理由があるものであった。時代と環境が変わった今、当時は適切だった規程が適切ではなくなっている。そのために変える必要がある。

この文書が提案する評価順序は以下の通り。

  • 後置式は左から右に評価される。これには関数呼び出し式とメンバー選択式も含まれる。
  • 代入式は右から左に評価される。これには複合代入も含まれる
  • シフト演算子のオペランドは左から右に評価される。

結果として、以下の式はすべて、a, b, c, dの順に評価される。

a.b
a->b
a( b, c, d )
b @= a
{ a, b, c, d }
a[b]
a << b
a >> b

オーバーロードされた演算子を使った式の評価順序は、組み込み演算子の評価順序と同じになる。関数呼び出しと同じ順序ではない。

P0147R0: The Use and Implementation of Contracts

現在提案されているcontracts案と似たような文法を使ってどのようなコードが書けるかという例示のための文書。contractsは、関数が満たすべきpreconditions, invariants and postconditionsを記述できる。

[PDF] P0148R0: memory_resource_ptr: A Limited Smart Pointer for memory_resource Correctness

memory_resourceをラップするスマートポインター、memory_resource_ptrの提案。

memory_resourceとは、ライブラリに追加される各種ヒープメモリーを実装したクラスのポリモーフィックな基本クラスだが、生のポインターを使うのはいろいろと不便なので、memory_resourceに特化したスマートポインターを追加する。

[PDF] P0151R0: Proposal of Multi-Declarators

多値を個々の変数で受け取る宣言文法として、以下のようなものがP0144で提案されている。

std::tuple< T1, T2, T3 > f() ;
auto { a, b, c } = f() ;

この文書は、以下のような別の文法を提案している。

tuple<T1, T2, T3><T1 x, T2 y, T3 z> = f(); // 多値のクラスと変数型の明示的な指定
tuple<T1, T2, T3><x, y, z> = f(); // 多値のクラスの明示的な指定
<T1 x, T2 y, T3 z> = f(); // 変数型の明示的な指定
<x,y,z> = f(); // 明示的な指定なし

また、使わない変数の省略を認めている。

// 2番めの変数は無視される
<a, c> = f() ; 

個人的には、autoキーワードを使う文法のほうがわかりやすいし、この文法が提案している柔軟な機能にどの程度の需要があるのか疑問だ。

P0152R0: constexpr atomic<T>::is_always_lock_free

コンパイル時にatomic<T>が常にロックフリーかどうかを確認できるconstexprメンバー関数is_always_lock_freeを追加する提案。

P0153R0: std::atomic_object_fence(mo, T&&...)

atomic_thread_fence(memory_order)に似ているが、指定したオブジェクトのみsequenced before関係を発生させるatomic_object_fence( memory_order, T && ... )の提案。

P0154R0: constexpr std::hardware_{constructive,destructive}_interference_size

std::hardware_constructive_interference_sizeとstd::hardware_destructive_interference_sizeの提案。

この2つのconstexpr関数は、一般にキャッシュラインサイズと呼ばれている値を取得するためのもの。

2つのオブジェクトがあり、ランタイムアクセスパターンがそれぞれ異なる(例えばあるオブジェクトは頻繁に変更するのに、もう一方のオブジェクトはほとんど変更しない)とする。CPUのキャッシュはキャッシュラインサイズと呼ばれる単位で行われており、この2つのアクセスパターンの異なるオブジェクトが同じキャッシュライン上に載っている場合、一方のアクセスパターンに引きづられて、本来必要のないキャッシュからメモリへの書き込みが行われてしまう。これをfalse-sharingと呼ぶ。

false-sharingを避けるには、異なるキャッシュライン上にオブジェクトが配置されるために、オブジェクトの配置されるメモリアドレスに十分なオフセットを儲けなければならない。hardware_destructive_interference_sizeは、false-sharingを避けるために必要な最小限のオフセットサイズを教えてくれる。

逆に、2つのオブジェクトのランタイムアクセスパターンが似通っていて、同じキャッシュライン上に載っている場合を、true-sharingと呼ぶ。true-sharingが行われるためには、2つのオブジェクトの合計サイズがキャッシュラインサイズに収まらなければならない。

hardware_constructive_interference_sizeはtrue-sharingされるための上限のサイズを教えてくれる。

この2つの値の定義は、実質の同じ意味なので、同じ値になるのではないかと思うのだが、2つに分けたのは、単にコードの意図をわかりやすくするためだろうか。それともこの値の異なる環境が実際に存在するのだろうか。

[PDF] P0155R0: Task Block R5

fork-join並列コードを書くためのライブラリ、task_blockの提案。

例えば、ツリー構造を並列実行でたどるときに

template<typename Func>
int traverse(node *n, Func&& compute)
{
    int left = 0, right = 0;
    define_task_block([&](task_block& tb) {
        if (n->left)
            tb.run([&] { left = traverse(n->left, compute); });
        if (n->right)
            tb.run([&] { right = traverse(n->right, compute); });
    });
    return compute(n) + left + right;
}

このように、define_task_blockに関数オブジェクトを渡すと、task_blockが実引数に渡される。あとはそのメンバー関数のrunを実行するたびに並列に実行が分岐する。

P0156R0: Variadic lock_guard (Rev. 2)

lock_guardをVariadic Templatesにする提案。

std::mutex m1, m2 ;

void f()
{
    // m1, m2に対してlock()が呼び出される
    std::lock_guard<std::mutex, std::mutex> lock( m1, m2 ) ;
    // 処理

    // lockのデストラクターでm1, m2にunlock()が呼び出される。
}

なお、make関数はない。lock_guardはコピーもムーブもできないからだ。

P0157R0: Handling Disappointment in C++

ある関数が呼び出し元の期待する処理を完了できなかった場合、呼び出し元は失望(disappointment)する。関数はその失望をどのようにして呼び出し元に伝えるのか。

この文書は、慣習的に使われている通知方法を列挙して考察している。

戻り値

戻り値は、最も一般的なC言語的手法であり、大抵はintかenumが使われる。失敗時には成功時特別可能な特別な値が使われる。この通知方法には問題がある。

エラー処理と通常の処理とが混ざってしまう。エラー処理が面倒なため、プログラマーはエラーを無視したがる。エラー処理に戻り値を使うと、通常の結果の値を戻り値ではなく実引数を経由した上書きで渡す必要が出てくる。呼び出し元がエラー通知に反応するには、事前に通知される値について知っていなければならない。

特別な戻り値

C言語で慣習的に用いられている方法で、戻り値を通常の結果通知に使うと同時に、特別な値を使って、エラー通知にも使う方法だ。特別な値には、nullポインターやゼロや-1などが用いられる。

この方法で通知できるのは、たいていはエラーの有無だけであり、エラーの具体的な内容については、別の方法で通知しなければならない。別の方法には、errnoのようなグローバルなオブジェクトが使われる。これは並列化を阻害する。

実引数を経由したエラー通知

これもC言語で慣習的に行われている方法で、実引数にエラー通知を受け取るためのオブジェクトへのポインターを取る方法だ。

これは、ループ文の条件式の中で使えないとか。エラー通知を完全に無視まではできないものの、結局無視されやすいという問題はある。

多値

関数の結果と、エラー通知の両方を多値で返す。これは古典的なC言語では行われていない方法だが、Goのような最近の言語では組み込みの多値を返す機能があるために使われている。

long jump

エラー通知にlong jumpを使う例が存在する。long jumpは関数内で起こった状態を解消するための手段を持たず、関数内で状態を持たないか、エラー発生時に状態を無視していい、極めて制限された環境でしか使えない。

例外

例外は上記のエラー処理の問題をいくつも解決している。通常のコードとエラー処理コードを分離できる。戻り値の型にデフォルトコンストラクターが要らない。補足されなかった例外はコールスタックを上がっていく。例外は未知のエラー通知にも使える。スタックフレームを遡る例外通知は、ローカルのオブジェクトを破棄していくため、エラー専用の破棄処理がいらない。

例外には欠点もある。まず例外は重い処理であるということ。頻繁に発生する「失望」を例外で伝えるには重すぎる。例外の存在は関数呼び出しにオーバーヘッドを発生させるので、極めて資源制約の強い環境では使えない。

エラーに対処してもう一度試行する処理を書けない。

論文では、様々なエラー処理を比較した結果、今後の規格は、現在提案中のexpectedやstatus_valueのような多値を返すエラー処理を推奨している。

P0158R0: Coroutines belong in a TS

コルーチンには様々な問題が山積みで、C++17に直接追加するのは時期尚早であるので、TSとして出すべきだと主張する文書。

現在コルーチンに持ち上がっている様々な問題が列挙されている。

Technical Specification for C++ Extensions for Concurrency, DTS

複数のfutureがready状態になるまで待つwhen_all、複数のfutureのうちどれかひとつがready状態になるまで待つwhen_any、futureのmethod chaining的に使えるメンバー関数then、wait_for, wait_untillatchとbarrier、atomic_shared_ptrといった並列同期に関するライブラリのTS。

ドワンゴ広告

今日は雪だったが、いつもどおりドワンゴ標準時で出社した結果、特に影響はなかった。

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

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

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

2016-01-12

C++標準化委員会の文書のレビュー: P0100R1-P0136R1

今回も改訂版文書のレビューをしていく。改定前の文書のレビューは同番号の過去の記事を参照。

本の虫: C++標準化委員会の文書のレビュー: P0100R0-P0109R0

P0100R1: Comparison in C++

比較の強さ別にカスタマイゼーションポイントとなる関数を用意する提案。

比較には、同一比較と、順序比較がある。順序比較には、partial orderとweak orderとtotal orderがある。これまで、順序比較にはoperator <などの演算子が、その種類を問わず使われてきた。どの比較を提供できるかは、型により異なるので、比較ごとの方法を提供できる関数テンプレートを追加する。カスタマイズするには、これをオーバーロードすればよい。

template<typename T> bool partial_less(const T&,const T&);
template<typename T> bool weak_less(const T&,const T&);
template<typename T> bool total_less(const T&,const T&);

template<typename T> bool partial_unordered(const T&,const T&);
template<typename T> bool weak_equivalence(const T&,const T&);
template<typename T> bool total_equal(const T&,const T&);

P0112R1: Networking Library (Revision 7)

Boost.Asioをベースにしたネットワークライブラリの提案。

変更点は、io_serviceをio_contextに、wrap()をbind_executor()に改名。package()をuse_futureの関数呼び出し演算子に、const_buffers_1とmutable_buffers_1クラスの廃止。const_bufferとmutable_bufferが直接要件を満たすことに鳴った。const_bufferとmutable_bufferにdate()とsize()メンバー関数を追加。buffer_cast<>とbuffer_size()の代替案。

P0136R1: Rewording inheriting constructors (core issue 1941 et al)

継承コンストラクターの文面を書き直す提案。これにより継承コンストラクターの挙動が僅かに変わるそうだが、影響はほぼない。

ドワンゴ広告

そういえば、今年からドワンゴで勉強会にも使っているセミナールームは歌舞伎座タワーではなく、ADK松竹スクエアの13階に変更になっている。

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

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

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

2016-01-11

GCC 6にインデントミスの警告機能が追加

GCC 6にインデントミス警告の機能が追加された。ドキュメントのコミットログは以下の通り。

gcc.gnu.or g Git - gcc.git/blobdiff - gcc/doc/invoke.texi

このインデントミスの警告機能は、-Wmisleading-indentationオプションで有効にできる。

if ( condition )
    foo() ;
    bar() ; // 警告

具体的に説明すると、この機能は、if, else, while, forの中の文がブロック文ではなく、かつ、文に続いて同じインデントのif, else, while, forではない文が続く場合に警告する。

例えば、以下のようなコードは、for文のオペランドとしての文に続いて同じインデントレベルの文が続くが、for文なので警告は出ない。


const std::size_t I = 10, J = 10, K=10 ;
int a[I][J][K]

for ( std::size_t i = 0 ; i != I ; ++i )
for ( std::size_t j = 0 ; j != J ; ++j )
for ( std::size_t k = 0 ; k != K ; ++k ) // 警告なし
{
    a[i][j][k] = 0 ;   
}

この警告は、プリプロセッサーにより生成された結果のコードには適用されない。

if ( condition )
    foo() ;
#if CONDITION
    bar() ; // 警告なし
#endif

理由は、プリプロセッサーによって生成された結果のコードは機械的に生成されたもので、人間が読むものではないから、人間向けのインデントは意味をなさないからだ。

ドワンゴ広告

今日は祝日で休みだ。

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

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

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

2016-01-09

Linus Torvalds、Microsoftが「ジャンプしてみろよ」と言えばIntelとAMDはジャンプする

LKML: Linus Torvalds: Re: [PATCH 0/3] TLB flush multiple pages per IPI v5

IntelのCPUのTLBの挙動に、頻出するパターンにおける最適化らしきものが施されていることが観測できることに対して議論した後で、

前にも言ったように、Transmetaで働いていた時期、俺はNT以前のWindowsがどういう世界だったかということを垣間見た。GDI protection traversalはGDIがカーネル側に入るたびにTLBを全部フラッシュするらしく、また当時の一部のグラフィックベンチマーク(これはまだハードウェア支援されたVGAグラフィックが一般的ではなかった時代のことだ)は、5千から1万命令以内にTLBを全部ふっとばす実装になっていた。そのため、IntelとAMDはTLB fillを高速にするために多大な労力を割くだけの理由があった。なぜならば、GDIベンチマークは当時重要だったからだ。当時のグラフィックベンチマークというのは、基本的な2Dウインドウ処理やフォント描画のベンチマークのことだ。

RISCベンダーは全く気にしなかった。奴らと来たら完全にクソなハードウェアで、ソフトウェアパートナー(大方はデータベース)に、ソフトウェアを変更して、large-pageを使うようにしたり、TLBミスを回避すべく努力させた。奴らのコンパイラーはロードを早期に行い、ストアを遅延させた。というのも、メモリサブシステムは完全にオモチャだったからだ。TLBミスはパイプライン全体をぶっ壊すなどしていた。本当にクソなハードウェアで、まだ期待している奴もいる。残念なことだ。

Windowsの業界では、そんなことは望みようがなかった。Microsoftが、「おう、ジャンプしてみろよ」と言ったならば、IntelとAMDはどちらも「どれだけ高く飛べばいいのでしょうか?」と言ったものだ。結果として、x86はどのRISCよりも柔軟だった。なぜならば、IntelとAMDはどんなクソなソフトウェアでも実行しなければならなかったからだ。ソフトウェア開発者に最適化をさせる代わりに。

ドワンゴ広告

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

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

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

x.orgドメインが消失の危機

X.Org Might Lose Its Domain Name - Phoronix

x.orgドメインが消失の危機に陥っているそうだ。

もともと、x.orgドメインは、X.Org Foundation LLCという団体によって登録管理されてきたが、x.orgがアメリカ合衆国における非課税の非営利団体 501(c)(3)に認定されるにあたって、この団体は解体された。

現在のX.org団体はx.orgドメインを管理しておらず、ドメインは1月19日に失効する。

x.orgドメインの登録時の連絡先は、Leon Shimanなる人物になっており、これはかつてアクティブに活動していた昔のX.org団体のメンバーの一人らしいが、連絡がつかないらしい。

2016-01-07

C++標準化委員会の文書のレビュー: P0022R1-P0092R1

今回も改訂版の文書のレビュー。改定前の文書は、以下の記事でレビューしている。

本の虫: C++標準化委員会の文書のレビュー: P0021R0-P0029R0

本の虫: C++標準化委員会の文書のレビュー: P0030R0-P0039R0

本の虫: C++標準化委員会の文書: P0050R0-P0059R0

本の虫: C++標準化委員会の文書のレビュー: P0060R0-P0069R0

本の虫: C++標準化委員会の文書のレビュー: P0080R0-P0089R0

本の虫: C++標準化委員会の文書のレビュー: P0090R0-P0099R0

P0022R1: Proxy Iterators for the Ranges Extensions

vector::iteratorのようなプロクシーイテレーターとそれ以外のイテレーターがうまく汎用的に扱えない問題を解決するライブラリの変更の提案。

これまで存在はするもののあまり活用されていなかったiter_swapを、例外的な挙動をするイテレーターのためのカスタマイゼーションポイントとして定義しなおすほか、iter_moveを追加する。イテレーターを操作する際は、このライブラリを使えば、プロクシーイテレーターを意識せずに扱うことができる。

また、共通の束縛できるリファレンス型を得る。common_reference traitsを追加する。2つのイテレーターのvalue_typeをcommmon_referenceに渡すことでコードを汎用的にできる。common_referenceはcommon_typeに似ているが、トップレベルのCV修飾子とリファレンス修飾子を削らない。

P0025R1: clamp: An algorithm to 'clamp' a value between a pair of boundary values -

clamp( value, min, max )で、valueがminより小さければminが、maxより大きければmaxが、それ以外の場合はvalueが返る関数clampの提案。

[PDF] P0030R1: Proposal to Introduce a 3-Argument Overload to std::hypot

3引数版std::hypotの提案。

[PDF] P0032R1: Homogeneous interface for variant, any and optional (Revision 1)

variant, any, optionalというtype erasure機能を提供する用途の異なるライブラリが提案されている。type erasureという機能では共通しているこれらのライブラリは、インターフェースがバラバラだ。インターフェースをある程度統一する提案。

[PDF] P0051R1: C++ generic overload function (Revision 1)

非情に面白いoverloadライブラリの提案。関数オブジェクトを突っ込んで、突っ込んだ関数オブジェクトの中でオーバーロード解決が最適なものを呼び出してくれる。

std::f = std::overload(
    []( int x ) { }, // #1
    []( double d ) { }, // #2
    []( auto x ) { } ) ; // #3

f( 0 ) ; // #1
f( 0.0 ) ; // #2
f( "hello" ) ; // #3

実装例は前回の記事で解説したが極めて単純で興味深い。

前回からの変更点としては、最適関数を選ぶoverload, 呼び出し可能な最初の関数を選ぶfirst_overload, 格納した関数オブジェクトにアクセスする機能の3種類に提案を分割し、それぞれ独立して提案することにしたらしい。

[PDF] P0057R1: Wording for Coroutines

コルーチンの文面案。変更点は、とうとうキーワードが決定されたこと。co_await, co_yield, co_returnになった。なんだか泥臭い名前だ。しかし、await, yieldなど使えるわけがない。

future<void> g()
{
   std::cout << "processing f" << std::endl ;
   co_await f() ;
   std::cout << "resumed" << std::endl ;
}

うーむ。バイク小屋バイク小屋。

P0061R1: Feature-testing preprocessor predicates for C++17

プリプロセッサーでのみ使える__has_includeの追加。ヘッダーファイルが存在するかどうかを調べられる。

#if __has_include(<any>)
#include <any>
using lib = std ; 
#elif __has_include(<boost/any.hpp>)
#include <boost/any.hpp>
using lib = boost ;
#endif

lib::any a ;

[PDF] P0083R1: Splicing Maps and Sets (Revision 3)

listにあるsplice機能をmapにも提供する提案。前回からの変更点は、node_ptrがnode_handleになったこと。operator *, operator ->が廃止され、かわりにmappedとvalueというアクセッサー関数が追加されたこと。空の状態を調べられるempty関数が追加された。機能テストマクロが追加されたなど。

mapが管理する内部の動的に確保されたメモリ上に構築されたノードの所有権をmapから切り離すことができる機能。

extractでmapからノードの所有権を切り離す。切り離されたノードはnode_handleクラスを経由して扱う。node_handleはアロケーターのコピーも持っているので、破棄された時にはノードも破棄される。キーを変更することもできる。mergeでnode_handleの所有するノードをmapにマージできる。

キーを変更して差し戻すことにより、余計なメモリの破棄、確保を省略することができる。

P0092R1: Polishing chrono

chronoライブラリに対する機能追加。丸めモードの設定、符号付きduration型にabsを追加する。

ドワンゴ広告

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

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

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

C++標準化委員会の文書のレビュー: P0001R1-P0018R1

内容は以下で解説しているものの改訂版。

本の虫: C++標準化委員会の文書2015-09 pre-Konaのレビュー: P0001R0-P0009R0

本の虫: C++標準化委員会の文書 2015-09 pre-Kona: P0011R0-P0020R0

P0001R1: Remove Deprecated Use of the register Keyword

registerキーワードの廃止。変更点はCとの互換性の一覧に追加。ドラフト入りした。

P0002R1: Remove Deprecated operator++(bool)

operator ++(bool)の廃止。変更は文面上の些細な間違いの修正にとどまる。ドラフト入りした。

P0004R1: Remove Deprecated iostreams aliases

iostreamのdeprecatedされていたライブラリを廃止。変更は互換性の一覧に追加。ドラフト入りした。

P0005R1: Adopt 'not_fn' from Library Fundamentals 2 for C++17

汎用的なnot_fnの追加。変更点はネストされた型名result_typeの削除。理由はISO/IEC JTC1/SC22/WG21 p0090r0による。

P0005R2: Adopt 'not_fn' from Library Fundamentals 2 for C++17

not_fnのさらなる改訂版。result_typeの復活。

P0007R1: Constant View: A proposal for a 'std::as_const' helper function template

実引数をconstなlvalueリファレンスとして返すstd::add_const。変更点は文面案の追加。

以下のような実装になる。

namespace std
{
    template< typename T >
    inline typename std::add_const< T >::type &
    as_const( T &t ) noexcept
    {
        return t;
    }

}

P0012R1: Make exception-specifications be part of the type system, version 5

P0012R1: Make exception-specifications be part of the type system, version 5

関数の無例外指定を型システムに含める提案、関数ポインターに無例外指定を型として含めることができる。変更は些細。

P0013R1: Logical Operator Type Traits (revision 1)

boost MPLにあるand_, or_, not_の提案。ただし、生枝がことなる。

前回の提案は、and_, or_, not_だったが、今回の提案では、議論の結果、名前が変わっている。それぞれ、conjunction, disjunction, negationとなっている。

template < typename T, typename U >
void f()
{
    // std::is_same_v<T, U> && std::is_integral_v<T> && std::is_signed_v<T>
    // と同じ
    constexpr bool b = std::conjunction_v< std::is_same<T, U>, std::is_integral<T>, std::is_signed<T> > ;
}

negationはともかく、conjunctionとdisjunctionは英語を母語とせず、数学の素養もなく、コンピューターサイエンスのアカデミックの経歴もない筆者にはわかりにくい気がするのだが、いいのだろうか。

とはいえ、この関数は初心者が使うものでもないし、これでいいのかもしれない。

P0014R1: Proposal to add the multiline option to std::regex for its ECMAScript engine

regexにECMAScriptにあるmutlilineオプションを追加する提案。multilineオプションを使うと、^と&の挙動が変わり、文字列の戦闘と末尾ではなく、文字列の各業の戦闘と末尾にまっ地するようになる。

P0017R1: Extension to aggregate initialization

基本クラスを持つクラス型をアグリゲート初期化できるようにする提案。

基本クラスを持つクラスはアグリゲート初期化できない。

struct base { int x ; } ;
struct derived : base
{
    int y ;
} ;

// エラー、derivedは基本クラスを持つ
derived d{ 1, 2 } ;

これに対し、直接の基本クラスを宣言順で初期化できるようにしようという提案。

// {1}はbase::xの初期化,
derived d{ {1}, 2 } ;

P0018r1 : Lambda Capture of *this by Value

lambda式で*thisをコピーキャプチャする機能の提案。

lambda式では、thisでキャプチャするのはポインターである。メンバー名を使った場合、キャプチャしたthisポインターを経由したアクセスが行われる。

struct X
{
    int member ;

    auto f()
    {
        // this->memberと同じ
        return [=]() { return member ; }
    }
} ;

クラスのオブジェクトの寿命が尽きた後もクロージャーオブジェクトを使いたい場合に、問題になる。

int main()
{
    std::function< int () > f ;

    {
        X x ;
        f = x.f() ;
    }// xの寿命、ここまで

    f() ; // エラー、xはすでに破棄されている。
}

C++14では、明示的なキャプチャー機能が追加された。

struct X
{
    int member ;

    auto f()
    {
        // memberはコピーされる
        return [ =,  member = member ]() { return member ; }
    }
} ;

問題は、データメンバーが複数ある時、これをいちいち書くのは面倒だ。明示的なキャプチャーで、クラスのオブジェクト自体をキャプチャーすることはできる。

struct X
{
    int member ;

    auto f()
    {
        // memberはコピーされる
        return [ =, self = *this ]() { return self.member ; }
    }
} ;

しかし、この例では、thisポインターは依然としてキャプチャーされてしまう。もし、self.memberのかわりにmemberと書いてしまうと、this->memberとして扱われる。極めて危険で間違いの元だ。

そこで、新しいラムダキャプチャーに、*thisを追加する。ラムダキャプチャーに*thisと書くと、クラスのオブジェクトをコピーする。


struct X
{
    int member ;

    void f()
    {
        // this->memberと同じ
        [this]{ member ; }

        // *thisを値でコピーする。
        // memberはクロージャーオブジェクトにコピーされたオブジェクトを参照する。
        [*this]{ member ; }
    }
} ;

つまり、以下のようなクロージャーオブジェクトが生成されると考えればよい。


struct closure_object
{
    // *thisをコピーする
    X unnamed_copy ;

    void operator () ()
    {
        unnamed_copy.member ;
    }
} ;

これは欲しい機能だ。

ドワンゴ広告

正月明けで昼夜逆転してしまった睡眠サイクルを強引に修正しようとした結果、DST(ドワンゴ標準時)から-4時間ほどずれてしまった。午前中に出社し、夕方過ぎに帰宅するようになってしまった。

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

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

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

yumetodoが本当に欲しかったもの

template引数として与えられた2つの型TypeFromとTypeToがあるとき、TypeFromからTypeToへの変換がintegral promotionsであるか判別し、そうであるならstd::true_type、違うならstd::false_typeを継承するクラスを作るにはどうかけばいいのか?

https://ask.fm/EzoeRyou/answers/134026904663

integral promotionsとは、C++規格の§4.5で規定されている。問題は、integral promotionsの内容を忠実に判定すると、charからshortへの変換はintegral promotionではないし、intからlongへの変換もintegral promotionではない。

それでもいいのであれば、実装は以下のようになる。

// check if from can be converted and represented to to.
template < typename from, typename to >
constexpr bool can_represent()
{
    return std::is_same< typename std::common_type< from, to >::type, to >{} ; 
}

template < typename from, typename to >
constexpr bool is_integral_promotion_impl()
{
// as per section 5.4 paragraph 6
    if ( std::is_same<from, bool>{} )
    {
        return std::is_same<to, int>{} ;
    }

// as per section 5.4 paragraph 3
    if (
            std::is_same<from, char16_t>{} ||
            std::is_same<from, char32_t>{} ||
            std::is_same<from, wchar_t>{} )
    {
        if ( can_represent<from, int>() )
            return std::is_same<to, int>{} ;
        else if ( can_represent< from, unsigned int>() )
            return std::is_same< to, unsigned int >{} ;
        else if ( can_represent< from, long int>() )
            return std::is_same< to, long int>{} ;
        else if ( can_represent< from, unsigned long int>() )
            return std::is_same< to, unsigned long int >{} ;
        else if ( can_represent< from, long long int >() )
            return std::is_same< to, long long int>{} ;
        else if ( can_represent< from, unsigned long long int>() )
            return std::is_same< to, unsigned long long int>{} ;
    }

// as per section 4.5 paragraph 3-4
    if ( std::is_enum<from>{} &&
        // requires lazy intantiation because underlying_type<T>::type is ill-formed for non enum T.
        std::is_same< to, typename std::conditional< std::is_enum<from>{}, std::underlying_type<from>, std::decay<void> >::type::type >{} ) 
    {
        return true ;
    }

// as per section 4.5 paragraph 1
    if ( !std::is_integral<from>{} ||
        !std::is_integral<to>{} )
    {
        return false ;
    }

    if ( std::is_same< to, int >{} &&
         can_represent<from, int>() )
    {
        return true ;
    }

    if ( std::is_same< to, unsigned int >{} &&
         can_represent<from, unsigned int>() )
    {
        return true ;
    }
         

    return false ;
}


template < typename from, typename to >
struct is_integral_promotion
    : std::integral_constant<bool, is_integral_promotion_impl<from, to>() >
{ } ;

ただ、fromがtoに変換できてかつ精度を落とすことなく完全に表現できる程度であれば、

template < typename from, typename to >
struct is_representable
    : std::integral_constant<bool, can_represent<from, to>() >
{ } ;

これぐらいでもいいのではないか。

しかし、constexprがあるのでこの手の処理は書きやすくなったと思ったら、std::underlying_typeのような問題がある。これを簡単に賭けるようにするため、constexpr_ifの導入が必要だ。

ドワンゴ広告

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

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

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

2016-01-05

C++標準化員会の文書のレビュー: N4553-N4567

[PDF] N4553: Working Draft, C++ extensions for Concepts

コンセプトTSのドラフト

[PDF] N4554: Editor's report for the Concepts TS

コンセプトTSのドラフト編集者の報告書

[PDF] N4555: February 2016 WG21 Meeting

2016年1月に開催される会議の告知

N4556: WG21 telecon minutes

2015年10月9日に行われた電話会議の議事録。

N4557: WG21 2015-07-20 Telecon Minutes

2015年7月0日に行われた電話会議の議事録

N4558:WG21 2015-11 Kona Minutes (Draft)

2015年10月19日から24日にかけて行われたKona会議の議事録。

[PDF] N4559: Kona WG21 Minutes

2015年のKona会議の議事録のドラフト。

会議の参加者とその所属一覧が興味深い。

また、Appleが投票権を失ったとも書いてある。最近人を出していないからなのだろう。

[PDF] N4560: Working Draft, C++ Extensions for Ranges

軽量コンセプトを用いたRangeコンセプトライブラリの提案、Range TSのドラフト。Rrangeコンセプトを定義することにより、コンテナーを直接アルゴリズムに渡すことができる。

std::vector<int> v ;

// 従来のイテレーター
std::sort( begin(v), end(v) ) ;
// Rangeコンセプト
std::sort( v ) ;

[PDF] N4561: Ranges Editor's Report

Range TSの編集者の報告書。N4560はRange TSの最初のドラフトであり、その内容はP0021R0に由来する。

N4562: C++ Extensions for Library Fundamentals, Version 2, Working Draft

標準ライブラリの提案。

意味的なconst性をメンバー関数を経由しても伝えるpropagate_const、汎用的なBM検索、ある型のオブジェクトを格納しているか、格納していない状態を表すoptional, どんな型でも格納できるany, 異なる文字列表現をラップしてくれるstring_view, 新しいメモリ確保のインターフェースと、新しいヒープメモリ確保の実装、所有しないバカポインターobserver_ptr, コンテナーに対するフリー関数版のerase, araryの拡張, 汎用的なサンプリングアルゴリズムの実装、GCDとLCMの実装、簡単に使える乱数ライブラリrandint, ソースファイルの情報を取得できるsource_location。などなど

[PDF] N4564: C++ Extensions for Library Fundamentals, Version 2 PDTS

N4562と内容は同じ。

[PDF] N4565: Record of Response: National Body Comments ISO/IEC PDTS 19571 Technical Specification: C++ Extensions for Concurrency

Concurrency TSに対するNBコメントに対する返答。日本からは文面の誤りと、コンテナーをvectorに限定せずに汎用的にするコメントが出された。文面の誤りは採用された。コンテナーを汎用にする提案は拒絶された。

n4566: Editor's Report -- Working Draft, Standard for Programming Language C++

C++ドラフトの編集者の報告書。

興味深いcore issuesの解決は以下の通り。

Core issue 1722が解決された。

lambda式のクロージャーオブジェクトの関数ポインターへの変換関数は無例外保証(noexcept(true))を持つようになった。

// 無例外保証
void (*ptr)() = []{} ; 

Core issue 1949が解決された。

規格は、AがBより先に処理されるという意味の、"A sequenced before B"という用語の意味を定義していて、この意味を表現する時はこの用語を統一して使うべきなのにもかかわらず、"B sequenced after A"なる表現がいくつかの箇所で見られるので、sequenced beforeに修正する。

core issue 2004の解決。

規格の文面を解釈すると、mutableなvariant memberがある場合に、constexprで型システムを壊して実行時書きかえができてしまう場合を修正。

  union U { int a; mutable int b; };
  constexpr U u1 = {1};
  int k = (u1.b = 2); // OK, bはmutable
  constexpr U u2 = u1; // おおっと?

core issue 2024を解決。pack expansionがテンプレートに依存するように規定する文面がないことを修正。こんな例が見逃されていたとは以外。

core issue 2026を解決。定数初期化にもゼロ初期化が行われるように解釈できる文面を修正。定数初期化ではゼロ初期化は行われず、明示的に初期化されない定数初期化は違法になるという従来の挙動を維持。これも考えると以外な見逃しだ。

core issue 2031の解決。C++11ではリファレンス修飾子として&&を追加したが、これは従来の演算子の&&と互換性の問題を発生させるコード例が見つかったので、それを互換性の項目に付け加える修正。

以下のようなコードが該当する。

  struct Struct { template <typename T> operator T(); };
  bool example_1 = new int && false;               // #1
  bool example_2 = &Struct::operator int && false; // #2

C++03では、#1,2ともに、&&は演算子であり、合法である。C++11では、リファレンス修飾子となるため、違法である。

まあ、まず書かないようなコードだ。

core issue 2052の解決。特殊化の結果生成されたシグネチャが組み込み演算子と同じだった場合を違法にする。

その他のドラフト入りしたコア言語の変更点。

registerキーワードの廃止, operator++(bool)の廃止。例外指定を型システムに取り込む変更、__has_includeの追加、非staticデータメンバーの宣言箇所における初期化に対して、default member initializerという名前をつける文面の変更、継承コンストラクターの文面の書き直し。

ライブラリの変更点としては、Adopt Type Traits Variable Templates from Library Fundamentals TS for C++17を追加したのがとても大きい。また、Variadic lock_guard (Rev. 2)も入った。

[PDF] N4567: Working Draft, Standard for Programming Language C++

現時点で最新のC++ドラフト規格。

ドワンゴ広告

新年初出社。

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

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

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

v

2016-01-03

江添ボドゲ会1月の調整さん

例のごとく、1月も木場にある筆者の自宅でボドゲ会をしようと思うのだが、人数と都合のいい日の把握のために、調整さんを作った。

江添ボドゲ会1月 | 調整さん

4人以上集まれば開催する。

2016-01-02

教えてgooのリコメンドが怪しい

正月の朝には雑煮を食べる慣習がこの2016年に存在する。筆者も慣習に従い、雑煮の調理を開始した。正月の雑煮の作り方は様々だが、共通項としては、具材に餅が含まれることと、だし汁で具材を煮込むことがある。今年の雑煮は、人参、しいたけ、たけのこ、鶏肉をゆでた上で、三つ葉も入れた。

鶏肉は、もも肉を使った。鶏肉は部位によって特性が違うが、特にもも肉と胸肉がよく使われる。もも肉は胸肉より高い。なぜだろうか。もも肉は胸肉よりも取れる量が少ないから高いのであろうか。しかし、せせり(首)は少量しか取れないが、それほど高くはない。もも肉は油が多く美味だから高く、胸肉は油が少なく調理方法を工夫しないとパサパサして美味しくないから安いのだろうか。すると、レバーはそのままでは臭みがあり、調理が面倒なのでとても安くなっているべきなのだが、そうでもない。

この疑問を解決するため、筆者はGoogleにお伺いを立てることにした。Googleは以下のURLを返した。

鶏肉はなぜもも肉より胸肉の方が安いのですか?- 素材・食材 | 教えて!goo

教えてgooは利用者同士の質問と回答をするためのWebサービスである。回答をみてみると、もも肉のほうが需要が高いからであるという意見が多かった。

出典がないが、需要の差というのは常識に照らし合わせて納得できる説ではある。

さて、右側に目を転ずると、「このQ&Aを見た人がよく見るQ&A」という項目があり、他の質問へのハイパーリンクが貼られている。これは、リコメンドと呼ばれる機能である。この質問の見た人に共通して特によく見られている別の質問は、この質問を見た人にとって見る価値がある可能性が高い。

しかし、そのリコメンドされた質問の候補が不思議だ。

  1. 鶏の胸肉はなぜ安い?- 素材・食材 | 教えて!goo
  2. 行為のときに、女性の体を見て幻滅したことある男性- 性の悩み | 教えて!goo
  3. 夫婦でのセックス頻度ってどれくらいですか?- 性の悩み | 教えて!goo
  4. セックス挿入について- 性の悩み | 教えて!goo

1はいいとして、2から4までの候補は、本当にこの質問を見た人がよく見ているのであろうか。まるで「胸」という単語に単純に反応したかのように思える。

第一、この質問から2-4の質問に直接飛ぶ方法が、このリンクしかないではないか。下のほうに、「胸」で質問を検索するURLが生成されているが、この検索結果は、女性が胸の悩みが多く、2-4の質問は出てこない。

他の質問を見ても、このように極端なリコメンドは存在しない・・・と思っていたが、ランキング上位のカテゴリー素材、食材の質問のリコメンドみると、やはり2-4が上位にきている。「胸」のような性の悩みに関連する単語すら出てこない質問だ。

なるほど、どうやら、「これを見た人がよく見るもの」という意味でのリコメンドは正しいようだ。2-4の質問はあまりにも閲覧者が多いため、食材に関する質問と言った、全く関係ない質問に対しても共通する閲覧者が多いためにリコメンドされてしまうらしい。一度リコメンドに乗るとハイパーリンクが貼られるため、その興味深い質問文につられてさらに閲覧者が増える効果も予想できる。そうなると、リコメンドが固定されてしまう。

リコメンドはもう少し工夫してほしいものだ。

2015-12-30

今年遊んだビデオゲームの感想

今年はFallout 4が発売されたため、久しぶりに大金を投じてゲーム用PC環境を構築した。今年遊んだゲームの感想を書いてみる。

何か他にも面白いゲームがあれば教えてほしい。筆者は一人称シューターが好きだ。ステルス要素は嫌いだ。Ubisoftのゲームはグラフィックだけの見せかけで肝心のゲームは中途半端で、かつUPlayというクソみたいなDRMがあるので避けることにしている。

Borderlands 2

FPS版Diabloといったゲームだ。レベルがあり、敵と武器の強さがレベルによってスケールする。武器の強さは乱数によってさらに増減する。前作と違い、ストーリーもなかなかよい。特に、ハンサムジャックという敵がとてもよい味を出している。サイドミッションにもボイスとストーリーが付いている。とても中毒性のあるゲームだ。

ただ、前作と比べて、とても死にやすいバランスになっている。

そして、ラスボスとDLCのラスボスが極めて退屈だ。ボスは巨体で弱い攻撃をしてくるだけなので、死にはしないのだが、HPが異常に高く、倒すのに時間がかかる上に退屈だ。

Borderlands: The Pre-Sequel

時系列的にはBorderlands 2の少し前のお話。ヒーローを目指すハンサムジャックが少しづつねじれていく。

基本的にはBorderlands 2のシステムを踏襲している。開発が2Kオーストラリアなので、オーストラリアネタが多い。特に、意図的にひどいオーストラリアのなまりが聞き取りにくい。

基本的なシステムは前作と同じなのだが、前作よりも改良されている部分もある。まず、Slag要素がない。B2はSlagがあるために、敵の硬さがSlagを前提に設定されていて、とにかく敵がタフだった。今作はSlagがないので、敵が柔らかめになっている。

Deus EX: Human REvolution - Director's Cut

悪くないゲームだとは思うが、退屈なステレスFPSで、筆者の好みのジャンルではない。

Duke Nukem Forever

開発に13年もかかった大作。あまりの発売延期に、Vaporware Awardを毎年もらっていた伝説のゲーム。

ただし、FPSゲームではなくて、パズルゲームだった。あまりにも期待されすぎたゲームではあるが、実際のところは、悪くないパズルゲームだ。10時間ぐらいは遊べるので、セール時に数百円で買えば納得できる。

なぜ13年も開発が続いたかというと、金があったからだ。Duke Nukem 3Dというゲームの売上と、そのゲームエンジンのライセンス料のおかげで、デベロッパーである3D Realmsにはうなるほど金があった。そのせいで、パブリッシャーは何も言うことができなかったのだ。

一般に、このような規模のゲーム開発では、パブリッシャーが出資をしてデベロッパーが開発する。デベロッパーはゲームの質を高めるために努力するが、パブリッシャーは利益を追求する。そのため、度々デベロッパーとパブリッシャーの対立が起こるものである。最終的に利益を出さなければならない以上、パブリッシャーは往々にして、「品質はそこそこでいいから早くゲームを出荷して利益を出せ」と迫るものである。

たまに非難されるデベロッパーとパブリッシャーの対立を完全に失くした一例がこれだ。結局、現実的な規模のゲームを具体的な納期を区切って開発しないと、際限なく開発が進み、そうこうしているうちに、コンピューターの性能が上がり、ソフトウェアも改良され、結局作り直しを余儀なくされる。

ディレクターのGeorge Broussardが新しいゲームをするたびに、そのゲームの要素をDNFに追加しろと要求するので、開発者の間では、Broussardに新しいゲームをプレイさせるなとまで言われたらしい。

The Elder Scrolls IV: Oblivion

昔懐かしいゲーム。当時何百時間も遊んだはずだ。

The Elder Scrolls V: Skyrim

時が経つのは早いもので、なんともう5年も前のゲームだ。神ゲーである。

Fallout 3

神ゲー。

Fallout 4

確かに、確実に改良されてはいる。特に、コンテナーからルートするときにゲームがポーズしないのはすばらしい。

しかし、問題も多い。UIが全面的にクソだ。Pipboyにこだわるせいで、インベントリ画面は、実画面の数割程度の領域しか使っていない。かつ、OblivionでMODが出たため、Fallout 3以降に取り入れられたKey ringがなくなっている。ホロテープと鍵とその他の雑多なアイテムが、すべてMISCというカテゴリに打ち込まれてしまい、さっき拾ったばかりのホロテープを再生するために数百個ものアイテムの中から目grepする必要がある。一体何を考えているのかわからない。

しかも、クエストが終わったあとも、一部のクエストアイテムがクエストアイテムのままになっていて、インベントリから出すことができない。これもMISC欄を圧迫する。

メインクエストは、New Vegas風に複数の勢力のどれかに属して分岐するようになっているが、大半のプレイヤーは寄り道のため、当初の廃墟を旅する目的はとっくに忘れ去っているだろう。

クエストの大半は印象に残らないが、唯一Silver Shroudだけが面白かった。

コンテンツ不足のため、100時間ほどプレイすると飽きる。

Fallout New Vegas

ほぼFallout 3の古臭いシステム上に作られているため、様々な制約があるが、クエストには興味深いものが多い。戦闘がつまらない。

Hard Reset

あの伝説のPain Killerを開発したPeople Can Flyの元開発者達が立ち上げたFlying Wild Hogの開発したオールドスクールシューター。神ゲー。

Keep Talking and Nobody Explodes

ビデオゲームというよりはボードゲームに近い。ビデオゲームとしては、爆弾を解除するゲームだ。爆弾の解除方法はマニュアルに記載されているが、コンピューターを操作して爆弾を解除する人間は、マニュアルを読むことができず、マニュアルを読む人間は画面を見ることができない。爆弾を解除する人間とマニュアルを読む人間は、口頭でやり取りをする。マニュアルは極めて複雑で伝達ミスによる失敗を生みやすい。極めて面白いゲームだ。ゲーム実況にも向いている。

Kerbal Space Program

ロケットを組み立てて飛ばす極めて難しいゲーム。筆者はまだ軌道にのせることすらできていない。

Metro 2033 Redux

シューターとしては微妙だが、世界観は悪くないゲーム。舞台は核戦争後のロシアで、地上は汚染されているため、人々は地下鉄のトンネルの中に住んでいる。通貨はミリタリーグレードの実弾だ。問題は、ストーリーが超自然的でそれほど面白くはないことか。

Metro Last Light Redux

前作のバッドエンドから続くストーリー。システムはほぼ同じ。こんども世界観は悪くはない。前作よりも拠点での生活感が感じられる。しかし、やはり文明崩壊後の世界にしては文明が残りすぎている。まともな生産設備もないくせに、なぜシームレスストッキングがあるのかとか、冷静に考えて食うものすら満足に作れないはずなのに衣食住と武器がやたらと豊富だったり、また狭い地下鉄内でナチ党と共産党の軍隊が戦争をしていたり、相変わらずストーリーは超自然的な存在との対話を軸にしたものであったりと、プレイヤー置いてけぼりの電波ストーリーとなっている。

Painkiller: Black Edition

あのPeople Can Flyが開発した神ゲー。

Painkiller Hell & Damnation

Painkillerのリメイク。バニーホッピングを再現している。なぜか時系列的には過去の5作の後のようだ。

POSTAL 2

トレーラーハウスに住む昨日ゲーム会社に就職したばかりの主人公、Dudeが職場に行って給料を受け取ったり、ミルクを買ったりする極めて平和的なお使いゲーム。神ゲー。最近、Paradice Lostという拡張も出たので、ひさしぶりにプレイするにも最適だ。

Serius Sam 3: BFE

Serious Samの伝統に忠実なオールドスクールシューター。ただし、後半のステージがクリアできない。

Serious Sam HD: The First Encounter

Serious Sam第一作のリメイク。理不尽な初見殺しのトラップが多い。

Shadow Warrior

あのPainKillerを開発したPeople Can Flyから離脱した元開発者達が立ち上げた、Hard Restも開発したFlying Wild Hogが開発したゲーム。今回はシューターというよりもmelee重視のゲームになっている。神ゲー。

A Story About My Uncle

Grappling hookを用いた3Dプラットフォーム。面白いのだが、最後の方の極端に難しい場所が進めずに止まっている。

購入を検討しているゲーム。

Portal

極めて有名なゲームだが、あまり3Dパズルプラットフォームは好きではないのでやる気にならない。

Dying Light

面白そうなのだが、戦闘が単調で10時間ぐらいで飽きそうだ。

Just Cause 3

パフォーマンスに問題を抱えている上、ランキングシステムのために常にサーバーと接続していて、コネクションはたびたびブチ切れ、ゲームメニューを開いただけで何分も接続待ちをするので、Steamをオフラインモードにした上でファイヤーウォールで外向きのパケットを遮断するworkaroundが取られているというクソな実装だと聞いている。「明らかに、地面のテクスチャはnVidia専用らしいぜ」とか、「俺のババアのほうがもう少しは速い」などという名言レビューを生み出したおそらく今年最大のガッカリゲー。

サバイバルクラフト系ゲーム

節操無く乱立していて、どれもEary Access。どのゲームもシステム上、Spawn Camperばかりになるようだ。

2015-12-29

AVGのクソみたいなChrome拡張の脆弱性

Issue 675 - google-security-research - AVG: "Web TuneUP" extension multiple critical vulnerabilities - Google Security Research - Google Project Hosting

アンチマルウェアソフトウェアのAVGが、クソみたいな脆弱性を含むChrome拡張を、Chrome拡張のインストールを阻止する仕組みを意図的に迂回して無理やり入れた挙句、脆弱性を生み出していたそうだ。しかも、脆弱性の指摘に対する修正案がお粗末すぎる。このようなセキュリティ的にお粗末な対応をするところが出しているセキュリティ用のソフトウェアは一切信用できない。読者の中にAVGを利用しているものがいたら、即刻に消すべきだろう。

ユーザーがAVG AntiVirusをインストールすると、"AVG Web TuneUp"という拡張idがchfdnecihphmhljaaejmgoiahnihplgnのChrome拡張が無理やりインストールされる。webstoreの統計によると、900万人のアクティブChromeユーザーがこの拡張を有効にしている。

この拡張は様々なJavaScript APIをChromeに追加する。どうやら、これによって、拡張は検索設定や新しいタブページをハイジャックできる。インストール方法はとても複雑で、このような拡張APIの悪用を防ぐために設けられたchromeのマルウェアチェックを迂回している。

とにかく、APIの多くがぶっ壊れている。添付した攻撃サンプルは avg.comのcookieを盗むことができる。また、閲覧履歴などの個人情報をインターネット上に公開させることができる。任意のコード実行につながるような脆弱性が含まれていてもおかしくはない。

Chromeの開発者は、怒りのメールをAVGに投げるが、返ってきたAVGの主張する「修正」は、拡張コードの実行を、以下のような条件で制約をかけるものであった。

var match = event.origin.match(/https?:\/\/.*\.avg\.com/i);

if (match ! null {
...
}

このコードの意図は、拡張の動作をAVGのoriginのみに制限するものだが、正規表現は極めて悪く書かれていて、例えば、"https://www.avg.com.www.attacker.com"のようなoriginも受け付けてしまう。かつ、AVGのWebサイトにXSS脆弱性が存在した場合、誰でも拡張によってもたらされた「機能」を利用できてしまう。

Chrome開発者がそのような返答メールを返したところ、こんどは、拡張の動作を"mysearch.avg.com" and "webtuneup.avg.com"をoriginとする場合のみに制限するとんちんかんな「修正」を送ってきた。これ以上改善の見込みがないと判断したChrome開発者は、以下のようなメールを投げつける。

見てみたが、この方法は動くだろう。ただし、ホワイトリストしたドメインがXSSやmixed contentを含む場合、誰でも脆弱性を活用できてしまう。

残念なことに、そういう脆弱性を発見するのは難しくない。私はWebセキュリティ専門家ではないが、数分探すだけで、以下を見つけた。

http://webtuneup.avg.com/static/dist/app/4.0.5.0/interstitial.html?risk=%3Cimg%20src=x%20onerror=alert(1)%3E&searchParams=%7B%22lang%22%3A%22en%22%2C%22pid%22%3A%22pid%22%2C%22v%22%3A%22vv%22%7D

わかりやすく説明してやると、このドメイン下にXSSバグが存在する限り、すべてのAVGユーザーは、銀行、メール、その他すべての個人情報が流出してしまう。そのため、このドメイン下は入念に保守と検証をする必要がある。

御社はホワイトリストされたドメインに対してプロのWebセキュリティ検証を行うという条件下で、この修正は動くだろうよ。

セキュリティ用のツールを開発しているところがこんなマヌケな「修正」を送ってよこすとは。AVGは一切信用できない。ちなみに、avg.comのXSS脆弱性は、未だに修正されていない。

思うに、もはやアンチマルウェアソフトウェアの時代は終わった。というのも、結局既知のマルウェアに特有のシグネチャを検出するのは何の訳にも絶たない。マルウェアを作り出すのはそれほど難しくはないからだ。マルウェアに特有の挙動を仮想環境上で動かして調べるというのも、誤爆が多く役に立たない。

それどころか、アンチマルウェアソフトウェアの殆どは、カーネルモードで動作するコードを追加したり、カーネルAPIをフックしたり、カーネルを書きかえたりする。それによって、新たな脆弱性を追加している。追加のソフトウェアは追加のリスクという古き良き教訓は忘れ去られてしまったのだろうか。

それに、この拡張によって一体どのようなセキュリティが確保されるというのか。筆者には、AVGが検索クエリーなどの個人情報を収集して販売するための機能にしか思えない。すると、AVGはマルウェアにほかならない。

このマッポーの世の中では年末といえどもまともなオーガニック・スシを食べることすらかなわない

年末なので贅沢にもツキジでコンベヤーベルト完備ではない高級オーガニック・スシをつまもうと出かけたが、このマッポーの世の中では、ニコチン中毒者によるキセル・パイプの害のないスシ・レストランは存在しなかった。

大抵のスシ・レストランは、エントランスにはいった瞬間にシガレット臭いアトモスフィアが流れてくる。とてもではないがオーガニック・スシを出すレストランだとは思えない。

落胆して、マケグミ・サラリマンのよく立ち寄る禁煙が保証されている合成ソバショップに入りかけたが、おお、ゴウランガ! とあるスシ・レストランの店先に、「カウンター 終日禁煙席」とショドーされているではないか。スシを補給するのにこれ以上の場所はあるまい。さっそく中に入り、カウンターチェアに腰掛けた。

しかしなぜか流れてくる煙たいアトモスフィア。振り返れば、タタミ一枚も離れていない距離にいる典型的なニコチン中毒者フェイスをしたサラリマンがタバコ・ドラッグをキメているではないか。看板に偽りあり!

筆者が普段外食を避けている理由はこれだ。このマッポーのトーキョーではレストランはニコチン中毒者の巣窟なのだ。ニコチンスモークが蔓延するアトモスフィアのレストランでまともなオーガニック・スシなど期待できるわけがない。

サラリマンの身分とはいえ、年末ぐらい贅沢をしたかったのだが、このマッポーの世の中では贅沢に値するオーガニック・スシ・レストランなど存在しないようだ。

2015-12-22

Linuxカーネル、Rockchip暦に対応

kernel/git/torvalds/linux.git - Linux kernel source tree

Linuxカーネルにあふれる文才と皮肉の無駄遣いを感じるコミットメッセージがある。

西暦1582年、ローマ教皇、グレゴリウス十三世は既存のユリウス暦が現実を十分に正しく表現していないことを見出され、不足分を補うために、うるう年を計算する規則を変更なされた。同様にして、西暦2013年に、Rockchipのハードウェアのエンジニアは、新しいグレゴリオ暦がまだ誤りを含むことを見出した。すなわち、11月は31日まで存在するよう改めた。遺憾ながら、暦の変更が広く浸透するには時間がかかる。先のプロテスタント国家がグレゴリウスの発案を受け入れてから、まだ300年しかたっておらず、すべての宗教とオペレーティングシステムカーネルがRockchip暦の改良を受け入れるにはまだ長年を待たねばならない。その時に至るまで、我々はRockchipのハードウェアから読み、そして書き込む日付情報を、グレゴリオ暦に変換する必要がある。

このパッチは、2016年1月1日を、Rockchip暦とグレゴリオ暦が同期している起点として定める。この起点から、起点移行の任意の日付を、11月から12月への変遷を何度経たかを数えて、2つの暦のオフセットを計算し、相互変換する。ハードウェアの日付を日常的に変更する方法ではなく、この方法を選んだ理由は、システムが不明な年数シャットダウンされたとしても日付を維持できる唯一の方法だからである。欠点は、同じハードウェアの他のソフトウェア(メインボードのファームウェアなど)も、RTCから正しいタイムスタンプを読み書きするために、同じ変換方法(起点も同じ)に従わなければならない。

短い翻訳:ロックチップのハードウェア内蔵の時計が、不具合により、11月は31日まであると認識しているので、存在しない11月31日が存在し、またそれにより毎年一日づつ現実のまともなグレゴリオ暦からずれていく。この問題をLinuxカーネル側で静かに修正するためのパッチ。

2015-12-21

ドワンゴにおける業務外Slackチャンネルのまとめ

はてな社内Slackでウォッチしている非業務チャンネル6選 - 平常運転

ドワンゴ社内Slackの非業務チャンネルを紹介 - ゆっくりしてない

ドワンゴ社内チャットにおける各言語別チャンネルの参加者数をグラフで表してみた:dwango エンジニア ブロマガ:ドワンゴ研究開発チャンネル(ドワンゴグループのエンジニア) - ニコニコチャンネル:生活

すでにまとめられているので三番煎じだが、ドワンゴにおけるSlackの業務外チャンネルをまとめてみた。

ドワンゴには今、1000人ぐらいの被雇用者がいるはずであるが、現時点でチャンネル数は1534ある。ゆっくりがまとめた19日より、わずか2日間で7個増えている。

#4gamer

チャンネルの由来は4Gamer.netだろうか。ビデオゲームについて話すチャンネル。

#boardgame

ボードゲームのチャンネル

#kusoge

クソゲの雑談をするチャンネルとしてはやらせようとしたが発言がない。

他にも、#e-sportsやら#pokerやら、ゲームに関するチャンネルが多い。個別のゲーム用のチャンネルが多数ある。

#boulder

#anime

アニメについて論ずるチャンネル

ボルダリング部のチャンネル

野球部やテニス部やダンス部などのチャンネルもあると思う。

#rookies2014 - 2014年新卒が多く集まるチャンネル
#rookies2015 - 2015新卒が多く集まるチャンネル
#rookies2016 - 2016新卒が多く集まる予定のチャンネル
#rookeis4015 - 4015年新卒が多く集まる予定のチャンネル(現在確認できる最も未来のためのチャンネル)

一時期、社内でゴミのような人間が#rookies20xxをひたすら増殖したことがあった。#rookies2099もあった気がするが、その時までドワンゴが存続しているのか、また存続していたとしても、現社員が生き残っているかは不明だ。

#drunk, #sake

飲み屋や酒について語るチャンネル。飲兵衛が多い。

#dev_null

どうでもいい技術的な雑談チャンネル

#unk

どうでもいい雑談チャンネル

#security

脆弱性のニュースがよく話題になる。

#yami

社員同士の不要品の闇取引所

#okane_nai

万年金欠気味のドワンゴ社員のたまり場。給料日前には特に発言が増える傾向にある。ゴミのような人間も入っている。

#okane_hontoni_nai

お金が本当にない人が入るチャンネル。ゴミのような人間も入っている。

#shakkin_aru

借金のある人が入るチャンネル。理由は奨学金からカードローンまで様々。家のローンのある人は話題にならないようだ。

#okane_aru

お金のある人が入るチャンネル。発言数は少ない。前回の発言は10月6日。ちなみに、#okane_naiは本記事執筆時点で発言がどんどん増えていく。Slackにおける発言数の多さと貧乏には相関性がある気がする。

#ossan

PC-98とかの話を得意げに語りだすと誘導されるチャンネル。オッサンにしか通じない雑談が多い。ちなみに、#obahanはない。

#office_love

残念ながらこのチャンネルで成立したカップルはまだ存在しない。

#office_live

かいしゃぐらし。残念ながらドワンゴにはシャワー室がなく、寝る場所も確保しにくいので暮らしにくい。

#kanojo_inai

「最終目標はこのチャンネルが不要になること」というトピックがすべてを物語っている。

#karesi_inai

現在彼氏のいない女性社員が男の出会いを求めて入るチャンネル・・・ではなく、単に野郎がわずかに入っているだけのチャンネル。ゴミのような人間にすら見放された。

#diversity

「思想・国籍・障害・人種・性別・年齢・価値観等の多様性と、会社や社外活動との関係について、幅広く考えるチャンネルです」とのこと。最近では夫婦同姓の強制に対する合憲判決や、女性の再婚六ヶ月禁止規定の300日超は民法の矛盾から無効判決などが話題になった。

#c_plus_plus

C++の雑談。

#perl

ドワンゴのslackにおけるプログラミング言語別チャンネルまとめ記事のあとに作られたチャンネル。参加者は少なく発言もない。

#lisp

トピックが「哲学」になっている。

その他、主要なプログラミング言語ごとにチャンネルが乱立している。

#kickstarter

kickstarterや、いかにもクラウドファンディングで出されそうなガジェットの雑談が多いようだ。

#free

自由について語るチャンネル。過去に自由ソフトウェア財団のグッズを共同購入したりした。

#*****

チャーハンを愛する人たちが大盛りチャーハンに挑戦するチャンネル。実質係数という独自の用語がとび交う。

#lunchpassport

ランチパスポートを活用する人たちが集うチャンネル

ドワンゴ広告

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

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

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

C++標準化委員会の文書のレビュー: P0130R0-P046R0

P0130R0: Comparing virtual functions

記述が貧弱だが、2つのクラスのオブジェクトの指すvirtual関数が同一のものかどうかを比較する機能が欲しいそうだ。


struct A
{
    virtual void vf() { }
} ;

struct B : A
{
    void vf() { }
} ;

struct C : A
{
    
} ;

void f( A * a1, A * a2 )
{
    // a1.vfとa2.vfが同じvirtual関数を指しているかどうか知りたい。
}

論文はC#にメソッドを比較する方法があることを挙げて、C++にも同等機能がほしいとしている。

論文著者は、どうやらEAのゲーム開発者のようだ。

[PDF] P0131R0: Unified call syntax concerns

Unified Call Syntaxに持ち上がっている懸念の考察と払拭。Bjarne Stroustrupが著者。

まず、Unified Call Syntaxとは、x.f(y)という式があったときに、まずxのクラスの呼び出せるメンバーfを探し、妥当なものが見つからなかった場合は、f(x,y)として呼び出せる関数fを探す。同様に、f(x,y)という式があったときに、まず呼び出せる関数fを探し、妥当なものが見つからなかった場合は、x.f(y)として呼び出せるか試す。

これによる利点としては、呼び出し側は、ライブラリがメンバー関数で実装しているのかフリー関数で実装しているのか気にする必要がなくなるので、より簡単に、より汎用的なコードが書ける。

例えば以下のような問題がある。

struct API
{
    void member( int ) ;
} ;

void user_code( API & api )
{
    // 呼び出し前に引数のチェックする拡張
    auto checked_member = []( API & api, int i )
        {
            assert( i > 0 ) ;
            api.member( i ) ;
        } ;

    api.checked_member( 123 ) ;
}

このようにユーザーが既存のクラスを拡張したとする。これはUnified Call Syntaxで想定されている使い方の一つだ。しかし、APIが後にchecked_memberを付け加えたらどうか。

struct API
{
    void member( int ) ;
    void checked_member( int ) ;
} ;

ユーザーコードの意味が変わってしまう。

Bjarne Stroustrupは、このような問題は珍しいし、我々は何十年もこのような問題に満足に[要出典]対処してきたし、実装は警告できるし、インターフェースを雑に拡張すべきではないし、名前空間を使えば問題は回避できるし、他の言語も似たような問題はあるが、それほど深刻な問題ではないとしている。

もうひとつ、テンプレートのルックアップの問題がある。

template < typename T >
struct X
{
    void f( T & t )
    {
        t.m() ;
        m(t) ;
    }
} ;

テンプレートの名前解決には宣言時に解決するものと、実体化時に解決するものがある。ADLは実体化時に解決する場合でないと働かない。m(t)の場合には、tは依存名でmはまだ宣言されていないので、ADLが働く。t.m()の場合、そもそもADLの働く余地がない。t.m()が実体化時に呼び出せないとわかった時には、すでに宣言時に解決されているので遅すぎる。

この問題は、t.m()に対して、宣言時にm(t)でも二重に名前解決をしてから、宣言時と実体化時のどちらで名前解決をするのか決定する

IDEについてさらっと流されているのが興味深い。IDEにとって、Unified Call Syntaxをまともに静的解析による候補表示に適用すると候補が多すぎて便利にならない問題が考察されていない。

P0132R0: Non-throwing container operations

無例外版のコンテナー操作を追加する提案。

世の中には、数百キロバイトしかRAMを積んでいない組み込み環境がある。そのような極端な環境でも、ネットワークもXMLパースもUIフレームワークもスクリプトもすべてやらなければならない環境がある。そのような環境では、例外のコストは支払うことができない。

このような組み込み環境では、メモリは貴重であり、固定サイズのメモリを保持し続けることは禁忌である。動的メモリ確保は失敗する可能性が日常的にあり、メモリ確保に失敗した時の対処方法は、直ちに終了することではない。

そのような組み込み環境でもC++の恩恵は受けたいと思っており、近年、標準C++に近づきたい要望がある。しかし、そのためには例外や、メモリ確保失敗時には原則直ちに終了するような設計の現在のコンテナーは使えない。

如何にして既存のコンテナーに無例外版の操作を追加するかということについて、いろいろと案があるが、どれも一長一短だ。

無例外版のオーバーロードを追加する案

bool push_back(nothrow_t, const T&);    
bool push_back(nothrow_t, T&&);   

別の名前を使う方法

bool push_back_nothrow(const T&);    
bool push_back_nothrow(T&&);   

アロケーターに例外の代わりにnullptrを返せるようにし、nullptrを返した時のコンテナーの挙動を規定する方法

アロケーターにメモリ確保失敗時に呼び出すコールバック関数を設定できる機能を追加する方法

コンテナーの特殊化を追加する方法

時間がかかりそうだ。

P0133R0: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0133r0.html

noexcept(auto)の保留にすると宣言した短い文書。

極めて一部の例にしか適用できないため。

P0134R0: Introducing a name for brace-or-equal-initializers for non-static data members

非staticデータメンバーに初期化子を書けるようになったが、この機能に対して名前が与えられていない。

struct S
{
    int x = 0 ;
} ;

現行の規格では、この機能は"brace-or-equal-initializer for a non-static data member"と言うことができる。

名前がないのは不便なので、デフォルトメンバー初期化子(default member initializer)という名前を与える提案。規格の文面もこの用語を使ったものに書き変える。

P0135R0: Guaranteed copy elision through simplified value categories

value categoryを変更し、コピー省略を規格で強制する提案。

新しいvalue categoryの定義では、glvalueはオブジェクトやビットフィールドや関数といった場所に対する計算で、prvalueはオブジェクトやビットフィールドや関数を初期化するための評価となる。

そして、以下のような例で、コピー省略を必須の挙動にする。


struct X
{
    int data ;
} ;

X f() { return X{123} ; }

X x = f() ; // コピー省略は必須

このようなコードは、たいていの実装でコピー省略ができる。しかし、依然としてコピーコンストラクターは呼び出し可能でなければならない。ユーザーもコンパイラーもコピー省略ができると了解しているコードでコピーコンストラクターの存在が必要になるのは変だ。Xがコピーもムーブもできない型の場合、型システムの都合上、動的確保せざるを得なくなる。

P0136R0: Rewording inheriting constructors (core issue 1941 et al)

継承コンストラクターの文面をわかりやすい定義に変更する提案。定義の変更により、継承コンストラクターの挙動に些細な違いが生じるが、概ね改良である。

Core Issue 1776: Replacement of class objects containing reference members

ややこしい型システム上の文面の変更、std::launderの追加。

P0138R0: Construction Rules for enum class Values

scoped enumを使ったstrong typedefの提案。

enumeratorの存在せず内部型が指定されているscoped enumは、リスト初期化を使うと縮小変換が起こらない限り暗黙に型変換できる。というルールを追加する。

// 内部型の指定がある
// enumeratorが存在しない
// scoped enum
enum struct Index : std::uint32_t { } ;

void f( Index index ) ;

f( { 1 } ) ; // OK

これにより、勝手に整数型に暗黙に型変換されず、またリスト初期化を使わない限り整数型で初期化できない、強い整数のエイリアスを作ることができる。

整数以外の型には使えない。

より一般的な強いtypedefとして、opaque alias提案がある。

P0146R0: Regular Void

void型を完全形にする提案。

結果として、void型の変数が作れるし、void型の引数が取れるし、void型のリファレンスも作れる。

void a ;
void & b = a ;
void f( void, void ) ;
f( a, a ) ;
void c[5] ;

このような変更をする動機は、テンプレートコードでの汎用性を高めるためだ。現在、voidは不完全型であり、テンプレートコードはvoidのためだけに特殊化を書かなければならない。voidが完全形になれば、そのような問題はなくなる、

互換性の問題は、それほど大きくないと考えられている。多くのユーザーはvoidが完全形になっても気が付かないだろう。ただし、いくつか問題はある。

現在、void型ひとつだけを引数に取る関数は、引数を取らない関数という文法的意味が与えられている。このため、依存名ではないvoidが単一で引数に使われていた場合、引数を取らない関数という意味にする例外的なルールが必要になる。論文では、いずれはこの文法を廃止したほうがよいとしている。

void型を完全形にしたことによるABI互換の崩れはない。なぜならば、void型は状態を持たないためである。

sizeof(void)が違法であることを利用したSFINAEは、現時点で広く使われていないので、それほど問題にならない見込みだ。

条件演算子の評価結果がvoidになる場合があるが、これについては互換性に対する詳細な考察が必要である。

sizeof(void)が0を返すと最適化に使えるが、しかし、その場合voidの配列が作れない。sizeof(void)は1を返すように規定するのが最善だろうとしている。

提案には文面案も付属している。

ドワンゴ広告

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

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

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

とても賢いコンパイラーの逆襲

The Hacks of Life: The Dangers of Super Smart Compilers

Clangの最適化が未定義の挙動を検出してコード片を消し去ってしまったことに引っかかった開発者の嘆き。

今日初めて、RenderFarmのDSF render(global scenaryを作成するのに使っている内部ツール)をClangで最適化コンパイルして実行した。

結果はsegfaultだった。これは驚きだ(そして自身消失だ)。というのも、最適化していないデバッグビルドは問題なく動くし、GCCでコンパイルされた最適化ビルドも正しく動く。-O0ではバグがない(つまり#if DEVコードのバグではない)ので、「最適化は何をやっているんだ」の時間だ。

大量のprintfと試行錯誤の結果、最適化は以下のようなコード片を丸ごとすっ飛ばしていることが判明した。

for(vector<mesh_mash_vertex_t>::iterator pts = 
   ioBorder.vertices.begin(); pts != 
   ioBorder.vertices.end(); ++pts)
if(pts->buddy == NULL)
{
   /* とても重要な処理 */
}

とても重要な処理はすっ飛ばされていて、実際、とても重要だった。

さて、なぜだ。buddyはポインターではない。スマートハンドルである。そこで、operator ==は単にポインターを比較しているのではない。コードをさらに深く探って見てみよう。ハンドルはポインターのラッパーであった。operator *は*m_ptrを返す。operator ==はnullとの比較が動くように特別に定義されている。

  template < class DSC, bool Const >
  inline
  bool operator==(const CC_iterator<DSC, Const> &rhs,
                  Nullptr_t CGAL_assertion_code(n))
  {
    CGAL_assertion( n == NULL);
    return &*rhs == NULL;
  }

もちろん、Clangは筆者よりとても賢いので、このコードについて物申すことがある。

合法なC++のコードでは、リファレンスはnullポインターを束縛することはできない。比較は常にfalseと評価されると推定できる。

やれやれ、これが問題だ。このoperator ==は、他の多くのコードと同じく、&*を使ってラッパーから生のポインターを得ている。&と*はお互いに打ち消しあうので、生ポインターが得られる。

ただし、Clangはとても賢いので、「ふむ、もし&*rhs == NULLの場合、*rhsはどうなる? NULLリファレンスではないか(rhsがNULLでそれをデリファレンスした場合だ)。そして、NULLリファレンスは違法なので、これは起こりようがない。このコードは*rhsが評価された瞬間に未定義の挙動となる。このコードは未定義の挙動であるからして(*rhsがnullオブジェクトである状況が存在すればだが、そんな状況は存在しない)、コンパイラーは何でもできるぞ! もし、*rhsがnullオブジェクトではないのならば、&*rhsはNULLと同一になることはない。したがって結果はfalseだ。さて、一方がfalseでもう一方が未定義ならば、関数全体を以下のように書きかえられる」

  template < class DSC, bool Const >
  inline
  bool operator==(const CC_iterator<DSC, Const> &rhs,
                  Nullptr_t CGAL_assertion_code(n))
  {
    return false; /* ほら、直してやったぜ */
  }

そして、Clangはまさにこれをしている。 つまり、if(pts->buddy == NULL)がif(false)になったので、重要な処理は絶対に実行されない。短期的な修正は以下だ。

for(vector<mesh_mash_vertex_t>::iterator pts = 
   ioBorder.vertices.begin(); pts != 
   ioBorder.vertices.end(); ++pts)
if(pts->buddy == CDT::Vertex_handle())
{
   /* do really important stuff */
}

これで、operator ==は2つのハンドルを比較するものが使われる。

  template < class DSC, bool Const1, bool Const2 >
  inline
  bool operator!=(const CC_iterator<DSC, Const1> &rhs,
                  const CC_iterator<DSC, Const2> &lhs)
  {
    return &*rhs != &*lhs;
  }

これも違法な未定義の挙動なのだが(&*をnullポインターに使うのは違法)、Clangは気が付かないようで、最適化はこのコードを消せない。このコードはポインター比較になった。我々の勝ちだ。

新しいバージョンのCGALはこの問題を修正していて、operator ->()が生ポインターを返すのでそちらをつかうようになっている。

Clangの援護をすると、プログラムの実行時間はseffaultを起こすまでは確かに早かった。

すべてのライブラリを最新版にアップデートしないことを笑うかもしれないが、3つか4つぐらいのコンパイラーやビルドシステムを使っている環境でライブラリをアップデートして、動かなかった場合の依存関係を全部解決するのは難しいので、とりあえず問題を解決した我々を糾弾しないでくれ。

2015-12-20

HTTPステータスコード451(政治的な検閲)が正式に承認される

mnot’s blog: Why 451?

draft-ietf-httpbis-legally-restricted-status-04

HTTPステータスコード451がIETFで正式に承認された。近いうちにRFCとしても発行される。

元ネタは、Ray BradburyのFahrenheit 451(華氏451)というタイトルの小説で、これはディストピアな検閲社会を描いている。

451の意味は、403(禁止/権限がない)と似ているが、正確な意味は、ドラフトを引用すると、以下の通り。

このドキュメントはサーバーオペレーターが、あるリソース、あるいはあるリソースを含むリソース群に対し、閲覧を検閲するよう法的な命令を受け取った時に使うHypertext Transfer Protocol(HTTP)ステータスコードを規定するものである。

このステータスコードは、法律や一般大衆の雰囲気がサーバーの運営に影響をもたらした時に透明性を高める情報開示のために使うことができる。この透明性はオペレーターとエンドユーザーにとって有益なものとすることができる。

RFC4924はインターネットの透明性を抑圧する勢力について考察している。その勢力にはコンテンツへのアクセスを禁止する法的な介入が含まれることは明らかである。参照先のドキュメントによる記述や、RFC4084のセクション4がしめす通り、そのような検閲の事実は公開されるべきである。

HTTPステータスコード451の採用には、結構な議論があったらしい。もともと提案したTim Brayと同志の者は、オンライン上における検閲の事実は開示すべきであると考えていた。403は単に「禁止されている」という意味だけで、「法的な理由により閲覧させることができない」という意味はない。

当初、IESGでは反対する委員も多かったようだ。というのも、HTTPステータスコードは限りある名前空間だからだ。400から499までしかなく、全てに意味が割り当てられてしまったあとは、もうどうしようもない。

とはいえ、賛同する委員も多く、また検閲事実の収集を自動化したいという声もあったため、採用に至った。

451はどのように使われるのか。すべての検閲が451を使うことは期待できない。451はネットワーク検閲フィルターの役割を果たすファイヤーウォールが使うことも考えられるが、おそらく現実的には、発信元のWebサーバーが使うだろう。Github, Twitter, Facebook, GoogleといったWebサイトはしばしば検閲を要求されている。

抑圧的な国家は、検閲されている事実をも検閲するため、451を返すこと自体が検閲されるだろう。その場合、市民は国家が自国民を検閲しているという強力なメッセージを受け取ることになるだろう。

2015-12-18

やねうらおが本当に必要だったもの

range-based forはコンピューター将棋で使えるのか? | やねうら王 公式サイト

やねうらおが、range-based forが使えないとこぼしている。しかしその利用例をみるに、そもそもrange-based forを使うべきではない。

range-based forは、イテレーターというコンセプト(まだコンセプト機能はC++にないが)に従っている。イテレーターはポインター操作をモデルとしている。

  • イテレーターは要素群の中のある要素を指していて、operator *で要素を参照できる。
  • イテレーターの指す要素は、operator ++で次の要素に移動できる。
  • イテレーターはhalf-openとなっていて、要素群の最後の要素のひとつ次の、何も指していない状態のイテレーターが存在する。これを番兵のように使い要素の端に到達したことを判定する

一方、やねうらおのコードは、本来イテレーターではないものを無理やりイテレーターのようにしている。Squareというのは、おそらくunscoped enumだ。(C++11ではscoped enumという強い型をもつenumが追加された。従来の弱いenumはunscoped enumと呼ばれる)。つまり整数型と番兵なのだろう。

したがって、やねうらおに必要なのはrange-based forではない。

ところで、記事中でやねうらおはCプリプロセッサーマクロを多用している。これは極めて醜悪だ。C++にはlambda式が存在するので、同等のコードはもっと綺麗に書ける。

おそらく、やねうらおが本当にほしかったのは、こういうものではないのか。

template < typename T, typename Func >
void yaneu_for( T i, T sentinel, Func func )
{
    for ( ; i != sentinel ; ++i )
    {
        func( i ) ;
    }
}


int main()
{
    yaneu_for( ZERO, NB,
        []( auto i )
        {
            // 処理
        } ) ;


    int hoge ;

    yaneu_for( ZERO, NB,
        [&]( auto i )
        {
            // lambda式の外の変数も使える
            hoge = i ;
        } ) ;
}

初期値iと番兵sentinelを指定すると、sentinelに到達するまでインクリメントしつつ関数オブジェクトfuncを呼ぶ。関数オブジェクトはlambda式を使うとその場に書ける。

ところで、range-based for文は、以下のように使う。

for ( for-range-declaration : range )
    statement

これは、以下のように展開される(多少の細部を省略している)

{ // 新しいブロックスコープ

    auto && __range = range ;

    for (   auto __begin = begin-expr,
                 __end = end-expr ;
            __begin != end ;
            ++__begin ) {
        for-range-declaration = *__begin() ;
        statement
     }
}

begin-exprとend-exprは、decltype(__range)の型次第で変わるが、いずれもbegin()/end()に相当する処理である。

具体的な例をしめす。以下のようなコードは、

std::vector<int> v{ 1, 2, 3 } ;
for ( auto i : v )
{
    std::cout << i << std::endl ;
}

以下のように展開される。

std::vector<int> v{ 1, 2, 3 } ;
{
    auto && __range = v ;

    for ( auto __begin = v.begin(), __end = v.end() ;
            __begin != __end ;
            ++__begin )
    {
        auto i = *__begin ;
        std::cout << i << std::endl ;
    }

}

v.end()は一度しか呼ばれない。

以下のような場合、

int a[100] ;
for ( int & i : a )
{
    i = 0 ;   
}

以下のように展開される。

int a[100] ;
{
    auto && __range = a ;
    for (   __begin = a, __end = a + 100 ;
            __begin != end ;
            ++__begin ; )
    {
        int & i = *__begin ;
        i = 0 ;
    }
}

それから、もはや現代でinlineを使う理由が思いつかない。

ドワンゴ広告

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

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

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

Ubuntuのカーネルをアップデートしたらカーネルパニックが起きた時の解決方法

昨日、何気なくUbuntuのアップデートをしたら、カーネルが4.2.0-19-genericから4.2.0-21-genericにアップデートされた。いや、正確にはアップデートする途中でdpkgがエラーを出しているようだ。何やら脳裏に不安がよぎる。

リブートすると、"kernel panic not syncing unable to mount root fs on unkonown-block(0,0)"と表示されて止まってしまう。

仕方がないので、ブート時にShiftを押し続けてgrub2のメニューを出し、アップデート前のカーネルである4.2.0-19を選んでブートした。Ubuntuは、少なくとも一つ前のカーネルは残すので、カーネルをアップデートして、何らかの理由でそのカーネルに不具合がある時は、以前のカーネルを使うことができる。

さて、どうするのか。毎回これでは不便なのでとりあえず問題のある新しいカーネルを消してみることにした。

sudo apt-get purge linux-image-4.2.0-21-generic

ただしこれはlinux-genericのような仮想パッケージも消してしまうらしい。apt-get upgradeしても、新しいカーネルが依存関係にないのでインストールされなくなった。

再びlinux-genericをインストールしてみる。

sudo apt-get install linux_generic

結果、linux-headers-generic, linux-image-genericなどのパッケージがすべて入る。

依存関係を解決するために、言われるままに以下のようにする。

sudo apt-get -f install

その結果、linuxカーネルの4.2.0.21をインストールしようとするが、やはりdpkgが途中で止まって、ブートできない。

エラーメッセージをよく見てみると、どうやら、dpkgがlinux-image-extra-4.2.0-21-genericの.debファイルを展開する際にエラーになっているようだ。カーネルに問題があるのではなく、ダウンロード済みのパッケージファイルが何らかの理由で破損しているのだろうか。

ダウンロード済みのパッケージファイルを削除するには、apt-get cleanを使えばよい。

sudo apt-get clean

この結果、パッケージファイルを再びダウンロードし、今度は正しく動いているようだ。年のためにリブートして確認してみる。リブートできた。

~$ uname -r
4.2.0-21-generic

やれやれ。

2015-12-16

Grub2の認証でバックスペースを28回押すとレスキューコンソールに入れる脆弱性が発見された

Back to 28: Grub2 Authentication Bypass 0-Day

Grub2のバージョン1.98(2009年12月)から、2.02(2015年12月)までにおいて、脆弱性が発見された。

脆弱性はGrub2の認証機能を使っていた場合に、ユーザー名を入力すべきところで、バックスペースを28回入力すると、レスキューコンソールに入れてしまうものだ。これにより、コンピューターに物理アクセスを得ている人間が、Grub2の強力なレスキューコンソール機能を使うことができる。

脆弱性の原因も詳しく書かれていて興味深い。grub2のコードでは、'\b'が入力されるたびに、unsigned型の変数をデクリメントする。この時、アンダーフローをチェックしていない。その変数は配列の添字に渡されて、ゼロが書き込まれる。

結果として、関数のreturn addressを0x0にすることができ、関数の終了時に戻って実行されるアドレス0x0になる。

通常のユーザースペースのプログラムやカーネルの場合、便利な保護機能が何重にもあるので、ここで終わりになるはずだが、grub2はブートローダーなので、そのような便利な保護機能はない。特殊な実行環境の結果、self-modifying codeを含むループに突入し、最終的に、grub_rescue_run()の先頭アドレスに飛ぶことで、レスキューコンソールに至る。

とても面白い。