lcamtuf's blog: HTTP cookies, or how not to design protocols
これは面白い。
今日、突然、画面上に不思議なウインドウがでた。何事かと思ってよく見ると、何とMcAfeeであった。おかしい。私はMcAfeeをインストールした覚えなどない。それに、このウインドウは、ブラウザのポップアップでもない。明らかに独自のウインドウである。南無三、やられたか。これはMcAfeeのフリをしたmalwareに違いない。しかし何故だ。そもそも最近は、ネット上から実行ファイルをダウンロードして実行ということすらしていないはずだ。
ともかく、どのようなプロセスなのか調べることにした。すると、なぜかファイルパスがProgram Files下にある。よく作ったものだ。まるで本物のMcAfeeのようだ。いや、まてよ、Program Files下だと? Program Files下に書き込むためには、Administrator権限が必要である。どうやってUACを突破したのだ。いや、仮にUACを突破したとしても、わざわざProgram Files下に書き込む必要はあるのか。malwareならば、もっと便利な場所がいくらでもあるだろうに。
不思議に思って調べると、スタートメニューにも、McAfeeの項目が付け加えられており、コントロールパネルの「プログラムと機能」にも、McAfeeのアンインストール項目が表示されている。どうもおかしい。偽物にしてはできすぎている。その表示を信じるならば、インストールした日は、2日前である。
2日前といえば、確かFlash Playerのアップデートをしたような気がする。まさか・・・そのまさかだった。クソAdobeは、デフォルトでクソMcAfeeをバンドルしているのだ。しかし、そんなオプション、全く気がつかなかったぞ。クソにも程がある。
つまり、このMcAfeeは本物らしい。Flash Playerのアンインストールを本気で考えてしまった。いずれにせよ、もう数年で、Flash Playerはいらなくなるだろう。
アンインストール後、念のためにMark Russinovichのautorunsを使って調べたが、見慣れない自動実行やサービス、ドライバーの類は見つからなかった。しかしまぁ、なんだかなぁ。
ニコニコ動画を見なくなって久しい。ところが、今日になって、ニコニコ動画からのSPAMメール(連中に言わせると、通知メール)が届き始めた。どうやら、誰かが自分のリストを購読するたびに、SPAMが送られてくるらしい。通知メールを送らない設定にもできるようだが、通知メールの種類があまりにも多く、一つ一つ手動で選択しなければならないという、クソふざけたUIとなっている。しかも、ひとつ設定するごとに、無効にしているメール一覧のページにとばされるので、そのままもう一つ無効にしようとしても、実は有効にしているだけだという始末。
バカにしているにも程がある。即座にアカウントを消した。
思えば、ニコニコ動画は、インターネット史に残るサービスではあったと思う。最初の一年ぐらいは面白かったが、ここ数年は、まともにみなくなっていた。遅い。埋め込み動画はChromeで見れず、一度埋め込み動画を再生しようとしてしまうと、公式サイトに飛んでも、その動画が読み込めなくなってしまう。そもそも、コメントが面白かったのは初期だけで、すぐに、常にコメントを無効にしていたのだ。
結局、ひとつの時代が終わったということか。
C++0xでは、unionの制限がかなり取り払われたので、こんなことができる。
union U { std::string str ; std::vector<int> vec ; // コンストラクターとデストラクターは、暗黙的にdeleteされているので、 // ユーザー定義が必要。 U() { } ~U() { } } ; int main() { U u ; new ( &u.str ) std::string( "hello" ) ; std::cout << u.str << std::endl ; u.str.~basic_string() ; new ( &u.vec ) std::vector<int> { 1, 2, 3 } ; for ( auto i : u.vec ) { std::cout << i << std::endl ; } u.vec.~vector() ; }
まあ、なんのことはない。Uのオブジェクトは、std::stringとstd::vector<int>のどちらかを格納できるだけのサイズを持っているし、またアライメント要求なども適切に行われるので、placement newができるという話だ。
最初、~basic_stringと書くべきところを、~stringと書いてしまい、エラーになった。typedef名の弊害と言える。もちろん、テンプレート実引数は省略できる。なぜならば、オブジェクトの型は、コンパイル時に分かっているからだ。
この手のことは、別に新しいテクニックというわけでもないが、自前でストレージのサイズやアライメントを設定せずにすむので、よりポータブルに書ける。
German tank problem - Wikipedia, the free encyclopedia
第二次世界大戦当時、連合国は、ドイツの戦車の生産台数を知りたかったが、その方法がなかった。
ドイツの戦車には、シリアルナンバーが付与されていた。捕獲した何台かの戦車から、そのシリアルナンバーを知ることができた。さて、このシリアルナンバーは、明らかに、インクリメントされている。すでに知っているいくつかのシリアルナンバーから、ドイツの戦車の生産台数を割り出すことはできぬものか。
そして、実際に、ほとんど同じ数字を割り出したらしい。なかなか興味深い。
今の世の中では、戦車の保有台数を隠すことに、あまり意味はないかもしれないが、極力敵国に情報を渡さないということを考えると、シリアルナンバーはUUIDなどにしておいたほうが無難なのかもしれない。
連合国はどうやってドイツの戦車生産数を割り出したのか - スラッシュドット・ジャパン
ちなみに、こんな話も。当時の日本人とアメリカ人の食事の違いで、大便の量が異なっていたため、誤った推定をしてしまったというお話。
MLに面白い話題が上がっていたので紹介する。
noexceptには、二つの意味がある。
1. 例外指定としてのnoexcept
void f() noexcept ; // noexcept(true)と同じ void g() noexcept(true) ; // 例外を投げない void h() noexcept(false) ; // 例外を投げる
この場合、文法は、noexcept( 定数式 )という文法になる。定数式がtrueと評価されれば、無例外といういみである。
2. noexcept演算子
void f() ; void g() noexcept ; int main() { noexcept( f() ) ; // false noexcept( g() ) ; // true }
この場合、文法は、noexcept( 未評価式 )となる。未評価式が例外を投げる可能性があれば、falseを返す。例外を投げないと保証できる場合は、trueを返す。例外を投げる可能性というのは、throw式が含まれているかや、noexcept(true)と指定されていない関数を呼び出すかどうかで判断される。たとえ、実際にはthrow式が含まれていなくても、無例外指定がされていない関数の呼び出しは、falseと評価される。noexcept演算子は、定数式である。
さて、以下の例を考えてみよう。
void f() noexcept( noexcept( g() ) ) ;
これはどういう意味かというと、g()という未評価式が、例外を投げる可能性がなければ、関数fは無例外指定されるという意味である。一方、
void f() noexcept( g() ) ;
これは、g()という定数式が、trueと評価された場合に、関数fは無例外指定になるという意味である。もちろん、g()という式が定数式でなければ、エラーとなる。
この文法はどう考えてもややこしくないか。
実は、以下のような文法も考慮されていたらしい。
void f() noexcept if true ;
ここでは、ifというキーワードを使うことによって、次に定数式を指定している。しかし、noexcept(true)の方が分かりやすいという意見の方が多かったため、こうなった。また、別の拡張で、似たような文法を使いたい時に困るという意見もあった。別の拡張というのは、ほかでもない、明示的なSFINAEである。
一週間前、つまり親知らずを抜いてから二週間目では、傷はふさがったものの、親知らずを抜いた影響で、親知らずの近くの歯が、何も悪くないのに痛んでいた。抜歯後、三週間もたった今では、痛みはない。しかし、親知らずを抜いた後が穴になっていて、モノを食べると詰まる。結果として、歯磨に苦労する。
shall not use a computer that contains any encryption, hacking, cracking, scanning, keystroke monitoring, security testing, steganography, Trojan or virus software.
is not to use a computer for any purpose other than school related assignments.
暗号の利用禁止ということであれば、SSLを利用したWebサイトは使用できなくなる。それどころではない。Webブラウザーやメールソフト自体が使用禁止だ。そもそも、WindowsやMacOSやLinuxといったモダンなOSは、暗号技術がふんだんに使われているので、使用禁止である。コモドールでも使うのだろうか。いやしかし、コモドールは暗号フリーだろうか。
それどころではない。テレビやゲーム、DVDなども使用禁止である。大昔の真空管テレビででもない限り、これらの機械には、暗号技術がふんだんに使われている。もちろん、DRMのかかった音楽や動画、電子書籍なども利用禁止である。また、電話も使えないだろう。
電子透かしも、DRMを利用不可能にする。しかし、現在では、多くの音楽CDに、電子透かしが埋めこまれている。つまりこの少年はCDを再生することすらできまい。
キーストロークモニタリングの禁止も厄介だ。なぜならば、現代のほとんどのソフトウェアは、キー入力を監視している。もちろん、OSはまず筆頭にあがる。キーモニタリングをしていないソフトウェアというのは、OSのカーネルのごく一部でしかないだろう。しかし、それ単体では存在できない。そもそも、BIOSからして、キーモニタリングしているではないか。
クラッキングやスキャニングの定義も曖昧である。セキュリティテストには、おそらくファイヤーウォールやアンチウイルスソフトなども含まれるであろう。これらも実に効果的に、OSを使用不可能にしている。あるコンピューターにウイルスが入っていないと断言することはできない。なぜならば、工場出荷段階で、HDDやフラッシュメモリやEPROMにウイルスが混入している可能性があるからだ。
もし、この少年の住んでいる家が、物理的なカギのかわりに、電子キーを用いていた場合、この少年は一人で家に入ることすらできないであろう。
裁判所の命令を守るためには、この少年は現代技術を排斥するアーミッシュ - Wikipediaの住んでいる場所に引越して暮らすしかないであろう。しかし、アーミッシュとて、道交法をまもるためにしかたなく、馬車にライトを取り付けたりしているのだ。果たしてそのライトには、一切のコンピューターと認められる電子回路が組み込まれていないものかどうか、心配である。
このように、現代社会における暗号の禁止は、単なるパソコンの利用の禁止以上の、あらゆる電子機器の使用禁止という意味を持つ。あらゆる電子機器の使用を禁止された場合、すでにその存在に依存した社会では、暮らしていけないだろう。一体どうしたらこんな馬鹿げた命令を下せたのか、理解に苦しむ。
詳しくは元ソースを参照してもらいたいが、これには抜け穴があって、「学校の宿題のために、学校内や家庭内の監視された環境なら使用可能」という文章がある。おそらく、あらゆる電子機器の利用が、学校の宿題という名のもとに行われるのであろう。そもそも、自宅のドアを自力で開けられなければ、専属の秘書でも雇わない限り、学校に登下校できないわけだし。
そもそも、「盗難バイクを受け取った」という罪が、どうしてコンピューターの使用不可という命令になるのか分からない。現代社会は、コンピューターなしでは、到底暮らしていけないというのに。たとえば、銀行にも行けない。信号機の利用はコンピューターの利用になるだろうか。
働く人たちが答える「質問ある?」スレまとめ - NAVER まとめ
一部、明らかに怪しいものもあるが、そこは、嘘を嘘と見抜く必要がある2ch.netならではだろう。
昔の2ch.netでは、この手のスレは、「某ですが何か?」などというスレタイだったものだが、最近は「某だけど何か質問ある?」という、普通の形に変わってしまっている。これも、2ch.netの大衆化に伴って、2ch語が廃れたためだろう。もっとも、この「某ですが何か?」というのは、あまり真面目なスレには用いられなかった記憶もあるが。たしか、「先行者ですが何か?」とか、「プログレッシブナイフですが何か?」などというスレばかりだったように記憶している。
思うに、隠語というものは、最初は小数の集団の中において使われていたのが、集団が増えるにしたがって、一般化するか、死語となってしまうかの、どちらかになるのであろう。例えば、寿司屋で食べ終えた後にもらうお茶の事を、「あがり」というが、これとて、もとは寿司屋の店員同士の符丁だったわけだ。
1日でどれだけディズニーキャラにサインをもらえるか | オモコロ特集
中の人はカリグラフィーの練習までしなけりゃならないのか。
そういえば、私は日本人でも珍しい、あのネズミの住む夢の国に入国したことのない人間である。私は小中高とド田舎で暮らしていたが、学校のクラスのほぼ全員は、一度はネズミーランドに行っていた。恐ろしい集客力である。
nested_exceptionは、例外をネストするための、簡単なクラスである。ユーザー定義のクラスから継承して使うことを想定されている。
struct CustomException : std::nested_exception { } ; int main() { try { try { try { throw 123 ; // 何らかのエラー } catch( int e ) { // ここで、元の例外の値を保持しつつ、別の例外を一時的にthrowしたい std::cout << e << std::endl ; throw CustomException() ; } } catch( CustomException e ) { std::cout << "CustomException" << std::endl ; std::rethrow_if_nested( e ) ; // 例外を処理し終わったので、元の例外をthrowする } } catch( int e ) { // 元の例外が、さらに外側のハンドラへ届く std::cout << e << std::endl ; } }
では、nested_exceptionの実装どうなっているのか。実は、特別なことはなにもしていない。以下のような実装になる。
namespace std { class nested_exception { private : exception_ptr ptr ; public: nested_exception() noexcept : ptr( current_exception() ; ) { } nested_exception(const nested_exception&) noexcept = default ; nested_exception& operator=(const nested_exception&) noexcept = default ; virtual ~nested_exception() = default ; // access functions [[noreturn]] void rethrow_nested [[noreturn]] () const { if ( ptr == nullptr ) terminate() ; else rethrow_exception( ptr ) ; } exception_ptr nested_ptr() const { return ptr ; } } ; } // namespace std
これは単に、コンストラクターでcurrent_exceptionを呼び出しているだけである。つまり、nested_exceptionを継承しなくても、自前のクラスに同じ機能を組み込むことも可能である。しかし、このコードは、誰が書いても同じようになる。わざわざ自前で書かなくてもいいように、nested_exceptionがある。
しかし、わざわざnested_exceptionを継承するのすら面倒ではないか。そう思った君は、一流のC++プログラマーの素質がある。プログラマーは、怠惰であればあるほど、優れているのだ。第一、自分でコードを書くのは、バグのもとではないか。そういうズボラな一流プログラマーのために、throw_with_nestedという関数が用意されている。これは、実引数のクラスが、nested_exceptionを継承していれば、そのままthrowし、そうでない場合は、自動的にnested_exceptionと、実引数のクラスとを継承した、何らかの型を生成してthrowするのだ。
// 俺様お手製の超スゲー例外クラス struct My_Ultra_Super_Deluxe_Exception { } ; void f() { try { // 例外を投げるかもしれない処理 } catch( ... ) { std::throw_with_nested( My_Ultra_Super_Deluxe_Exception() ) ; } }
このようにすれば、例えば、以下のように書けるわけだ。
void g() { try { f() ; } catch( My_Ultra_Super_Deluxe_Exception & e ) { // My_Ultra_Super_Deluxe_Exceptionに対する例外処理 // ネストしている場合、元の例外を再throwする std::rethrow_if_nested( e ) ; } }
このようにすれば、元の例外を保持しつつ、別の例外を投げることができる。ハンドラ側では、ある例外に対する処理を行い、もしネストされていれば、再び例外をthrowすることができる。
throw_with_nestedの実装例は、本の虫: pre-Batavia mailingの簡易レビューを参照。throw_if_nestedも、ほぼ似たようなメタプログラムで実現できる。
もちろん、これらの関数は、すべて自前で実装可能である。ただし、一流のメタプログラマーではない限り、このようなメタプログラミングをするのは難しいので、標準ライブラリが用意されているのだ。
ISO/IEC JTC1/SC22/WG21 - The C++ Standards Committee
N3139: An Incomplete Language Feature
関数の実引数に、空の初期化リストを渡せない問題の修正。以下のようなコードがwell-formedになる。
struct S { S( std::initializer_list<int> ) ; } ; // デフォルト引数に空の初期化リスト void f( S s = { } ) ; int main() { // 関数の実引数に空の初期化リスト f( { } ) ; }
N3140: Cleanup of Pair and tuple
C++0xの新機能に対応させようとしたら、std::pairとstd::tupleの文面がだいぶおかしくなってしまったので、これを統一して修正。
N3142: Adjustments to constructor and assignment traits
has_*_constructorとhas_*_assignというtraitsは、あたかもコア言語的な響きがする。しかし、ライブラリ作者としては、ある型Tがコンストラクターを持っているかどうかは、別にどうでもよい。ライブラリ作者が知りたいこととは、ある型Tに対して、T()とか、T(U)などと書いてよいかどうかである。したがって、hasという名前は相応しくない。
すべてのhas_*_constructorとhas_*_assignという名前のtraitsを、is_*_constructibleと、is_*_assignableという名前に変える提案。
N3143: Proposed wording for US 90
現行のstd::forwardの定義では、以下のコードがコンパイルできない。
#include <utility> struct Base { Base(Base&&); }; struct Derived : private Base { Derived(Derived&& d) : Base(std::forward<Base>(d)) { } }; // error: forward can not access Derived's private Base
なぜならば、DerivedからBaseへのキャストは、Derivedクラスの外からは、アクセス指定の制限のため、行えない。すなわち、std::forwardの中では、行えない。この問題は、std::forwardを、lvalue referenceとrvalue referenceでオーバーロードすることによって解決する。また、std::moveのreutrnに、static_castが抜けているので、あわせて修正。
やはりstd::moveのreturnにstatic_castが抜けているのは規格の間違いだったのか。だいぶ前にstd::moveを自分で実装して、おかしいと思ったのだ。
throw_with_nestedの文面の修正。Tがnested_exceptionを継承していない場合、Tとnested_exceptionを継承したクラスが、forwardによって構築されて投げられるらしい。実装例はこんな感じだろうか。attributeを消し、using宣言をtypedefに置き換えれば、gccで動くことを確認。最近書くコードは、こんなのばかりだ。まったくもって実務的ではない。
namespace std { namespace detail { template < typename T > struct unspecified_exception : public std::remove_cv< typename std::remove_reference<T>::type >::type, public std::nested_exception { template < typename U > unspecified_exception( U && u ) : T( std::forward<U>(u) ) { } } ; template < bool b > struct throw_with_nested_impl { template < typename T > [[noreturn]] static void invoke( T && t ) { throw std::forward<T>(t) ; } } ; template<> struct throw_with_nested_impl<false> { template < typename T > [[noreturn]] static void invoke( T && t ) { using type = typename std::remove_cv< typename std::remove_reference<T>::type >::type ; static_assert( std::is_class<type>::value, "throw_with_nested:T must be a non-union class type.") ; throw unspecified_exception<type>( std::forward<T>(t) ) ; } } ; } // namespace detail template < typename T > [[noreturn]] void throw_with_nested( T&& t ) { using plain_T = typename std::remove_reference<T>::type ; constexpr bool b = std::is_base_of< std::nested_exception, plain_T >::value ; detail::throw_with_nested_impl<b>::invoke( std::forward<T>(t) ) ; } } // namespace std
N3145:Deprecating unary/binary_function
名前通り。
N3146:Recommendations for extended identifier characters for C and C++
C++0xでは、Basic source character set外の文字を、識別子として使うことを許可した。具体的にどのような文字が許可されるのかは、実装に依存するが、規格での推奨事項(空白文字は好ましくないなど)を付け加える提案。
N3148 - throw() becomes noexcept (Version 2)
N3149 - From Throws Nothing to noexcept
N3150 - Removing non-empty dynamic exception specifications from the library
名前通り。throw()をnoexceptで置き換えと、Throws: Nothingをnoexceptに変更することと、空ではない動的例外指定を削除。
N3151: Keywords for override control
N3163: Override Control Using Contextual Keywords
Rapperswill会議において、attributeのbase_check、override、hiding、finalは、キーワードで置き換えることが、投票により決定した。問題は、キーワードをどうするかということだ。もちろん、キーワードは、既存のコードの互換性を確保するため、絶対に使われていないような名前でなければならない。そのため、ML上ではbikeshedding(どのように自転車小屋を建てるべきかという、正直どうでもいい議論)が盛んであった。
キーワード案が採用されるならば、とてつもなくuglyなキーワードが採用されることは確実である。ここで、Contextual Keyword(文脈依存キーワード)という案がある。これは、ある名前を、ある特定の場所でのみ、キーワードとして扱うというハックである。JavaやC#が、すでにこれをやっている。このようなハックは、コンパイラーや文法ハイライトの実装を難しくする。ただし、C++はすでに、他の言語とは比べものにならないぐらい実装が難しい言語である。この程度の実装は、他のもっと難しい昨日の実装に比べれば、屁みたいなものである。それに、このような実装をすれば、ユーザー側の負担は全くない。既存のコードを再コンパイルするコストは計り知れないのである。
N3152: Progress guarantees for C++0x
C++0xは、マルチスレッドとデータ競合に関して、Progress guaranteesというものを、全く定義していない。これでは、プログラマがまともにコードを書くことなど不可能ではないか。というNBコメントに対して、progress guaranteesというものを厳格に定義することは、非常に難しいということを説明したペーパー。
N3154: US 19: Ambiguous use of "use"
規格の文面では、useという言葉が使われている。ところで、3.2では、useという言葉を、特別な意味を表す用語として定義している。しかし、文面では、useを一般の英単語としても使っており、区別がつかない。そのため、3.2のuseを、odr-useという特別な用語に置き換えることにする。3.2の意味でuseという単語を使っている文面も、odr-useに置き換える。
N3155 - More on noexcept for the language support library
N3156 - More on noexcept for the diagnostics library
N3157 - More on noexcept for the General Utilities Library
既存の標準ライブラリの中で、noexcept指定できる関数を模索。
N3158: Missing preconditions for default-constructed match_result objects
名前通り。
N3164: Adjusting C++ Atomics for C Compatibility
C1XとC++0xのatomicの互換性の向上
N3165: Allocator Requirements: Alternatives to US88
allocator_traitsの導入によって、allocatorのrequirementsが大幅に減った。では、実際に規格上のrequirementsも弱めるべきか。C++03との互換性はどうするのか。といったことを論じている。このペーパーにおける提案は、LegacyAllocator Requirementsを付け加えるというものである。ちなみに、legacy_allocator_adaptorというwrapper classを追加しようというアイディアは、却下された。
N3166=10-0156 - Destructors default to noexcept
例外指定のないデストラクターは、デフォルトでnoexcept(true)にしようという提案。一般に、デストラクターから例外を投げるべきではない。すでにC++98の段階で、、STLの全クラスは、デストラクターからの例外のthrowを禁止されている。また、STLに渡すテンプレート実引数の型も、デストラクターから例外をthrowしてはならないと定められている。C++0xでは、デストラクターは明示的にnoexcept(false)などを指定した場合のみ、例外を外に投げられるようになる。
N3167=10-0157 - Delete operators default to noexcept
delete演算子を、デフォルトでnoexceptにする提案。当然、deallocation functionも、この影響を受けて、デフォルトでnoexceptになる。
N3168: Problems with Iostreams Member Functions (Amended from US 137)
また誰にも使われないiostreamの修正か!
N3169: A Few Small Library Issues
これも名前通り。
futureをどのような目的で使うかということに関して、委員の間でも、意見の不一致がみられた。そこで、futureをどのような場合に使うかという例を示す。また、小さな文面の修正も含んでいる。
N3171: Proposed resolution for US104: Allocator-aware regular expressions
regexがbasic_stringに指定するアロケーターに関して、意味を明確化。
N3172: Allocators for stringstream (US140)
stringstreamがbasic_stringに指定するアロケーターに関して、意味を明確化。
N3173: Terminology for constructing container elements (US115)
コンテナーの文面で、要素の構築に関して、CopyConstructibleとMoveConstructible、引数による構築を、事実上、再定義してしまっている。これを、あらかじめ定義された用語を使うように修正。
暗黙的なムーブコンストラクターとムーブ代入演算子の生成は、C++03のコードとの互換性の問題を引き起こす。ゆえに、規格から消すべきである。題して、「暗黙のムーブは死ぬべき」
ムブるべきか、ムブらざるべきか、それが問題だ。ここでは、暗黙に生成されるコピーとムーブによる問題点を列挙している。筆者は、たとえ暗黙のムーブがなかったとしても、暗黙のコピーにより、問題は残ることを論じた上で、現状のFCDの文面を保持するべきだと結論している。また、暗黙のコピーは、ユーザー定義のコピー、ムーブ、デストラクターがある場合、生成をdeprecatedにするべきだと提案している。
つまり、この問題は暗黙のムーブだけではなく、暗黙のコピーにも起こりえるのだ。暗黙のムーブが生成されない状況では、暗黙のコピーも、本来、生成されるべきではない。いまからコピーに対してそのような変更を行うのは無理なので、せめてdeprecatedにするべきだと提案している。
N3178: emplace Broken for Associative Containers
現在のemplaceの定義では、連想コンテナには適用できない。この修正は、現時点では、容易ではない。さてどうするかという短いペーパー。そもそも、STLのコンテナーは、現代からみれば、設計が悪いのだ。だからemplaceなんてものが必要になる。やれやれ。互換性ハ神聖ニシテ侵スヘカラス。
N3179: Move and swap for I/O streams (US138)
basic_istream, basic_ostream, basic_iostreamにおいては、ムーブコンストラクターは、実はムーブしない。ムーブ代入演算子も、実はムーブしない。swapも、実はswapしない。しかも、これらの関数はprotectedであり、ユーザーコードからは使用できない。
しかし、これらのクラスはabstract classではないし、ユーザーコードから使用すべき妥当な理由もある。まあ、これもiostreamだ。したがって誰にも省みられることのない修正と言える。
マスコミやGIGAZINEが伝えないマジコン規制の本当の恐ろしさ - P2Pとかその辺のお話@はてな
現在、私の知る限り、DRMが掛かっている書籍、ゲーム、音楽、映画などは、残すに価するほどのものはない。だから、残すという話は、私にとってはどうでもいい。DRMをかけたことによって、将来的に困るのは、コンテンツホルダー側である。彼らの作品は残らないのだから、どんなに作品が人気であったとしても、将来、それによって得られたはずの利益が得られなくなるはずだ。
ただし、一体マジコンのごときものを法律で禁止するのは、危険である。所有しているコンピューターを、どのように使おうが、所有者の自由であるはずだ。マジコンが禁止されるということは、その自由を奪うということである。
もっともDSは、自由にプログラミングできないようなコンピューターである。そんなコンピューターは、始めから所有する価値がない。そして、DSというハードも、将来残らないだろう。
IBM PC/AT互換機は、いまだに残っている。これは、彼らが独占的な権利を主張しなかったからである。もし当時のIBMが排他的な考え方をしていたならば、今のIBMのPC市場で地位はなかっただろう。
親知らずを抜いてから二週間。傷はふさがったが、親知らずがあった場所の隣の歯が痛む。つまりは、一番奥の歯ということだ。特に今朝は酷い。
これはどうすべきなのかよく分からない。表面上、虫歯はないようだ。しばらく痛みが続くようならば、もう一度歯医者に良く必要があるのだろうか。
当時の予告編
リメイク
だいぶ頑張ったようだ。それでもやはり、体の震えを完全に止めることはできないらしい。
Visual C++ 10: 10 is the new 6 | VisualStudio | Channel 9
まあ、確かにVC6と同じくらいクソだということは確かだ。一行に数十文字ぐらい書いただけでクソ遅くなるIDE付きなのだから。C++の規格準拠度も、あきれ返るぐらい悪い。実に悪い。
本の虫: いまだに変な宗教が流行っているを書いたところ、どうもこのへんの情報は、あまり知られていないようであるので、できるだけ分かりやすく解説することにした。
Cの標準ライブラリは、恐ろしく古いライブラリである。その設計は、マルチプロセッサ(コア)上で動作するマルチスレッドが当然の現代では、あまりよろしくない。
たとえば、strtokという関数がある。この関数は、引数として渡された文字列を、内部のバッファにコピーする。次のstrtokの引数には、NULLを渡すことで、そのコピーされたバッファから、次のトークンの場所へのポインターを返すのである。
void f( char const * ptr ) { char const * p1 = strtok( ptr, " " ) ; char const * p2 = strtok( NULL, " " ) ; }
しかしもし、strtokが複数のスレッドから呼ばれた場合、どうなるのだろうか。引数にNULLを渡して、先程の文字列のコピーから、次のトークンの場所を返してくれることを期待しているのに、別のスレッドによって、勝手に内部の文字列が書き換わってしまっては困る。
この、複数のスレッドから利用しても大丈夫かどうか、ということは、非常に重要である。これをスレッドセーフと呼んでいる。
したがって、あるスレッドがstrtokを呼んでも、別のスレッドの内部バッファまで変更しないように実装しなければならない。これには、スレッドごとに、メモリーを確保する必要がある。
Cの標準ライブラリには、このようなスレッドアンセーフな設計のライブラリが山ほどある。Cの標準ライブラリは、まともなC++プログラマーならば、まず使おうとは思わないだろう。
言うまでもなく、このような設計は、現代ではクソである。当時のプログラマーを問い詰めたいところなのだが、まあ、すでになされたものは仕方がない。今さら互換性を失うわけにもいかないのだ。クソなことにはかわりはないが。
さて、このような、スレッドごとの動的に確保されるメモリーのアドレスを保持しておくための変数が必要になる。Windowsでは、TLS(Thread Local Storage)という仕組みが、OSによって用意されている。これにアドレスを格納しておけばいいのだ。
Windowsには、CreateThreadという、スレッド作成用のAPIが存在する。しかし、MSVCでは、独自のスレッド作成用の関数、__beginthreadexを使用することが推奨されている。これはなぜかというと、標準ライブラリに必要な、スレッドごとのメモリを確保、解放するためである。
では、もしMSVC上で、CreateThreadを用いてスレッドを作成したら、どうなるのか。スレッドごとの動的に確保されたメモリーを必要とする、一部の標準ライブラリは、動かなくなるのだろうか。幸い、その心配はない。MSVCの標準ライブラリの実装は、スレッドごとの動的なメモリーを必要とする関数が呼ばれたときに、TLSを確認し、もし、メモリーが確保されていなければ、その場で確保して、何事もなかったかのように処理を続ける。これによって、「動かない」という最悪の自体を回避できる。
しかし、ここでひとつ、問題がある。その確保したメモリーは、いつ解放すればいいのだろうか。もちろん、スレッドが終了するとき、すなわち、スレッドというリソースが解放される時である。しかし、スレッドの終了をどうやって補足すればいいのか。スレッドの終了を補足する方法は、なかなかにややこしい。
スレッドが、プロセスの終了まで、ずっと生存しているのならば、問題はない。Windowsにおいては、プロセスの所有するリソースは、プロセスというリソースの解放に伴い、自動的に解放されるからだ。プロセスが解放されたとき、後には何も残さない。もちろん、他のプロセスがプロセスハンドルを掴んでいる場合は、プロセスハンドルを維持するためのリソースは生き残っているが、それはまた別の話である。プロセスのスレッドはすべて開放されているが、まだプロセスが開放されていない状態である。
問題は、CreateThreadによるスレッドの生成、一部の標準ライブラリの仕様、スレッドの破棄を繰り返すプログラムである。そのようなプログラムでは、スレッドを生成、破棄するたびに、解放できないメモリーが取り残される。すなわち、リソースリークである。
実は、DLLを使えば、このスレッドの終了を補足するのは、非常に簡単である。なぜならば、プロセスに読み込まれている、すべてのDLLのDllMain関数は、プロセスのあらゆるスレッドの終了時に、DLL_THREAD_DETACH通知を受ける。この通知を使えば、TLSに保存されているアドレスのメモリーを解放できるのだ。
つまり、DLL版のランタイムライブラリを使えば、CreateThreadやThread Poolによって生成されたスレッドから、一部の標準ライブラリを使っても、リソースはリークしない。スレッド終了時に、必ず解放される。しかし、スタティックリンク版は、この方法が使えない。そして、MSVCの実装も、何とかするようには出来ていない。結果、リソースリークする。
そもそも、他ならぬマイクロソフト自身が、スタティックリンク版を使うなと明言したのが、確かVS2005の頃だった。スタティックリンク版のCRT、ANSI版のAPI、Unicode以外の文字コード、Windows XP、x86の32bitコード、IBM PCのBIOS、これらは皆、速やかに滅ぶべきものどもである。いやしくもプログラマーたるものは、実装の美しさを尊ばねばならぬ。特に、64bitコードの関数の呼び出し規約の統一は、涙が出るほどありがたいはずだ。それにも関わらず、旧態依然の古めかしい知識と技術に固執する。愚かなること、これに過ぎたるはなし。
追記:はてなブックマークのコメントより、
前半は良いのだが、後半のCreateThread()でのメモリリークについては、ちょっと最新の仕様とあってない気がする。Windowsは途中からスレッドハンドルをクローズしなくてはならない仕様になった
これはCRTとは何の関係もない話である。これはWin32 APIの仕様だ。この記事は、Windows、MSVC環境下における、スレッドとCRTのリソースリークについて書いているので、Win 32 APIの仕様には特に触れなかった。
ただし、これもスレッドとリークに関連はある。もちろん、CreateThreadで得たスレッドハンドルは、CloseHandleによって解放しなければならない。なぜならば、CloseHandleを呼び出さなければ、まだスレッドハンドルを、そのプロセスで使っているということだからだ。もちろんこれは、CreateProcessにおけるプロセスハンドルにも言えることだ。してみれば、Win32 API全般に関する注意点であって、特にスレッドに限定される話ではない。
7 things you really don't need to take a photo of - The Oatmeal
1. 酒場
「このマンゴーティーニ頼んだの、だあれ?」
「あたしに決まってんだろボケ。いまからさ、写真とって世界中に見せびらかそうよ。あたしらがこんなにもバカやってるところをさ。マジでオランウータンみてーじゃん、あたしら」
「マジでチョーサイコー。ゲロ吐くまで飲も飲も」2. 食べ物
「この食べ物は芸術的で、まさに写真を撮るに値するよな。まあ、ただ単に、俺がいまクソ腹減ってるってだけなのかもしれないけどさ。実際は、たいしたことないんだろうけど」
「ああ、ものすんげーウマそうだ。一生覚えてるだろうな。このマヨネーズポークサンド。我が心の友よ」3. 風景
「見ろよあの森を。もう感動しかないな。おい、すぐに写真を取れ、マーシャ。その写真を後でどうこうするわけじゃないけど、知ったこっちゃないし、すぐに写真撮ったことすら忘れるけど、そういうもんさ。まあともかく、メモカを滝や山なんかのゴミ写真で埋め尽くそうじゃないか。悪くないだろ」
4. ライブ
「ところで、これは何だい? 見たところ、チカチカ光ってるボケボケの何かの画像のようだが」
「昨夜のライブだよ。僕は、昨日、ライブを生で楽しむかわりに、携帯のクソ品質のカメラで、決定的瞬間を逃さぬように写真を取るのに熱中してたんだ」5. キス
「僕達の関係がすんげーいいってことを見せつけるために、オットセイみたいに唇をぶつけ合ってる写真をとっておこう」
「オッケー」6. 車
「珍走団速度まで加速するのに60秒しかかからないんだぜ」
7. 洗面所での自分撮り
[翻訳を諦めた]
相変わらずoatmealだ。ぬこの画像が含まれていないということは評価できる。
プログラミング :: 高速なプログラムを書く為に :: 初めに
ランタイムとして DLL を使用しない様にしましょう。DLL の設定にすると、 例えば cos や sin 関数を呼び出すのに dll を使用する (本来 CPU の命令 fcos を一回実行するだけの筈) など、 御馬鹿な事になるからです。数値計算に於いて、頻繁に呼び出す基本関数が dynamic link になっているというのは最悪です。
MSVCでスタティックリンクのマルチスレッドのランタイムライブラリを使ってはならない。リソースリークが完全に防げないからだ。DLL版は、DllMainでDLL_THREAD_DETACHを補足することによって、CRTに必要なリソースを開放しているので、リークは起こらない。
そもそも、DLLを使用しない理由というのが、cosやsinというのは、馬鹿げている。/Oiも知らないのだろうか。
標準レイアウト(standard-layout)とレイアウト互換(layout-compatible)の条件や、保証されている挙動を詳しく執筆したが、果たして日本人のC++プログラマーのうち何人が、ここまで詳しい解説を望んでいるのだろうかと疑問になった。
実際、この条件と挙動が規格によって保証されているというのは、C++にとって、非常に重要である。つまり、オブジェクトの内部表現に互換性があるというわけで、他の言語とのやり取りにも使える。
しかし、あまりにも厳密な定義は、果たして一般のプログラマーの役に立つであろうか。これらは、多くの場合、「なんとなく動く」とか、「この環境では動く」程度の認識しかされていない。広く一般に、どのような条件を満たせば、どのような挙動が保証されているのかということを把握しているC++プログラマーは少ない。
もちろん、language-lawyerたる私からすれば、全C++プログラマーは、これらの条件と保証される動作を知っておくべきである。そもそも、C++が必要とされる現実的な分野には、これらの挙動には、まずお世話になるはずである。
Implicit Move Must Go « C++Next
暗黙のムーブは深刻な互換性の問題を引き起こすから、削除しようとのこと。
問題点としては、C++03のコードは、暗黙のムーブを考慮せずに書かれてきた。もちろん、暗黙のムーブなんてものは存在しなかったのだから、これは当然である。しかし、以下のような場合、
// well-formedなC++03のコード // C++0xではill-formed class C { public: C() : v(5) { } ~C() { std::cout << v[0] << std::endl ; } private : std::vector<int> v ; } ; int main() { C a = C() ; }
C()によって生成される、prvalueの一時オブジェクトは、暗黙のムーブによって、ムーブされる。std::vectorは、ムーブ可能だからだ。しかし、std::vectorをムーブしてしまうと、もはや要素にアクセスすることはできない。しかし、C()によって生成される一時オブジェクトのデストラクターが走る際、メンバーであるvの要素にアクセスしている。これはエラーとなる。
このコードは、C++03ではwell-formedだが、C++0xではill-formedとなる、互換性のないコードである。
やはり、暗黙のムーブは、あまりにも登場が遅すぎたと言わざるをえない。これに対して、いくつか解決方法が考えられた。たとえば、ユーザー定義のデストラクターがあるばあい、暗黙のムーブの生成をしないようにしようというものだ。しかし、その場合でも、やはり互換性の問題がある。ついには、privateなメンバーを持つクラスは暗黙のムーブを生成しないようにしようなどという意見まででてきた。しかし、それでもなお、この問題は解決しない。
というわけで、暗黙のムーブは、残念ながら、ドラフトから取り除くべきだというのが、Daveさんの意見のようだ。ただ、デフォルトのムーブの動作は、なかなか便利なので、例えば = default ;によって、明示的にデフォルト化された場合は、暗黙のムーブを明示的に生成するような機能を残すのもいいのかもしれない、とも言っている。
いずれにせよ、互換性は言語の進化への大いなる障害だと言わざるをえない。言語の普及のためには、どうしても必要なのだが。
Windows 95において、もっともよくテストされたゲームは、DOOMである。これは別に、テスターがテスト計画をよく練ったり、テストが自動化されていたためではない。そういうわけではないのだ。これはただ単に、Windows 95の開発部のメンバーに、DOOMで遊んでいた人間が多かったというだけの話である。
DOOMがついに、DOS窓で動いたことは、大いなる前進であった。わざわざMS-DOSモードで起動する必要がなくなったわけなのだから。つまり、他のプログラムを終了させずに、DOOMを起動できるようになったのである。
聞くところによると、Windows Vistaにおいては、もっともよくテストされたゲームは、World of Warcraftだったそうである。DirectXアプリケーションの互換性部門の人間の多くや、Windowsの他の部門の人間は、WoWプレイヤーであったからだ。
そんなわけで、パソコン用の有名なゲームを持っているとしたら、Windowsの各部門にも、所有者があふれかえっているだろうことは、容易に予測できる。「品質保持の観点からも、特に保証できる次第である」
ちなみに、関連のリンク先は、Raymond Chenの著書にも載っている有名な話である。その内容とは、当時、自社製品のNICを負荷テストする最良の方法は、サンプルをMicrosoft社に送りつけることであった。なぜならば、まだインターネットが唯一の標準のネットワークプロトコルではなかった当時、もっともNICを酷使する環境にあった会社は、Microsoft社の社内ネットワークだったからだ。
この人は、Windows Internalsを読むべきである。
$Bitmapとは、NTFSのメタデータである。一応、Windows Internalsによると、Windows XP以降ならば、NTFSはリードオンリーでマウントできると書いてある。
ただし、Windows Internalsの記述から判断するに、通常、WindowsがNTFSをマウントする際には、ディスクは書き込み可能でなければならない。NTFSはマウントの際にリカバリーを実行するし、マウント後も、5秒ごとにログファイルへの書き込みが発生する。
問題は、今手元にあるWindows Internals 4thの、NTFSのリードオンリーの記述が、限りなく短いことだ。リードオンリーなメディアをマウントできるとしか書いてない。Windowsは、ディスクをマウントするさいに、ディスクへの書き込みに失敗した場合、自動的にリードオンリーでマウントしてくれるのだろうか。あるいは、リードオンリーでマウントするためには、ディスクやそのドライバーが、このメディアはリードオンリーであると話さなければならないのだろうか。その辺の記述は見当たらないので、分からない。
5thでは、増補されているのだろうか。
抜糸を行った。最後までしぶとく残っていた痛みは、やはり糸のせいだったらしい。
昨日から、少し固形物が食べられるようになってきた。しかし、まだ完全とは言いがたい。
糸をとった後も、どうもまだ痛む。もうしばらくかかりそうだ。
C++0xでは、std::allocator_traitsの導入によって、アロケーターに最低限必要なものが、かなり減った。これにより、アロケーター実装者の負担も減っている。メモ替わりに書いてみる。
以下は、std::allocator_traitsを通してアロケーターを使う場合に、最低限必要なものである。
// 必ずテンプレートパラメーターをひとつ取らなければならない // T型のオブジェクトに対するアロケーター template < typename T > class allocator { public : // 最低限必要なnested type typedef T value_type ; // ストレージの確保用 // n個のT型のオブジェクトを確保できるに足るだけのストレージを返す value_type * allocate( std::size_t n ) ; // ストレージの解放用 // pが指すn個のストレージを解放する void deallocate( value_type * p, std::size_t n ) ; // DefaultConstructibleである必要はない // コピーできなければならない // 例外を投げてはならない allocator( allocator const & ) noexcept ; // ムーブできなければならない // 例外を投げてはならない // 必要に応じて、ムーブコンストラクターも追加 // template argumentの違う他の型からの変換関数、コピーとムーブが両方可能であること // 例外を投げてはならない template <class U> allocator( allocator<U> const & ) noexcept ; // デストラクターは例外を投げてはならない // これは、STLの決まりごと ~allocator() noexcept ; // 他のオブジェクトと比較できなければならない // template argumentの違う他の型とも、比較できなければならない // a == bにおいて、お互いのallocateで確保したストレージが、お互いのdeallocateで解放できる場合、trueを。 // そうでない場合、falseを返す template < typename U > bool operator == ( allocator<U> const & ) ; // ==演算子の否定を返す template < typename U > bool operator != ( allocator<U> const & ) ; } ;
この他のメンバー、たとえばconstructとかdestroyとか、細々としたnested typesなどは、std::allocator_traitsを通して使う場合、適当に補完される。実を言うと、allocateやdeallocateも補完されるのだが、通常のユーザーが、自前アロケーターを書く目的は、そこにはないだろう。
追記、value_typeという名前のnested typeが必要であった。
thread_local指定子は、クラスのメンバーの際には、static指定子と共に宣言しなければならない。
void f() { thread_local int x ; // 暗黙のうちにstatic } struct S { // 宣言、staticも必要 static thread_local int x ; } ; // 定義、staticを使ってはいけない thread_local int S::x ;
ここで、S::xの定義には、staticは使えない。なぜならば、staticデータメンバーの定義は名前空間スコープに書くわけで、そこでのstatic指定子の意味は、staticストレージではなく、internal linkageだからだ。
何故このような制限があるのか分からない。メンバーの宣言にも、暗黙のstaticを認めてもいいと思うのだが。第一、thread_localによって宣言された変数は、thread storagedである。static storageではない。
何故このような制限があるの変わらかないと書いたが、全然思い当たらないでもない。結局、static storageとは別に、static data memberという概念があるために、こうなっているのだろう。全然別の事を、ひとつのキーワードで行わせるのは、混乱のもとだと思う。
あるクラスがstandard-layout classの条件を満たしたときに保証される動作はいくつかあるが、その中でもとくに重要なものに、クラスのオブジェクトへのアドレスは、クラスの最初の非staticデータメンバーのサブオブジェクトへのアドレスに等しい。というものがある。
struct A { int x ; int y ; } ; A a ; A * a_ptr = &a ; int * ptr = reinterpret_cast<int *>( a_ptr ) ;
この場合、ptrはa.xを指す。これは規格で保証されている。ちなみにこの時、++ptrがa.yを指す保証はない。なぜならば、実装はデータメンバーの間にpaddingを入れるかもしれないからだ。ともかく、このクラスのオブジェクトへのアドレスが、クラスの最初の非staticデータメンバーへのサブオブジェクトのアドレスに等しいというのは、重要な保証だ。
ところで、standard-layout classとなるためには、かなり厳しい条件を満たさなければならないわけだが、その中に、「最初の非staticデータメンバーと、基本クラスとで、同じ型を使わない」というものがある。
// standard-layout classではない例 struct A { } ; struct B : A // 基本クラス { A a ; // 最初の非staticデータメンバー int data ; // 二つ目の非staticデータメンバー } ;
なぜかというと、基本クラスのサブオブジェクトと、データメンバーaは、別々のアドレスを割り当てられていなければ、困るからだ。
struct A { } ; struct B : A { A a ; } ; B obj ; A * p1 = &obj ; // 基本クラスのサブオブジェクトへのアドレス A * p2 = &obj.a ; // データメンバーへのアドレス // p1 != p2が保証される
なぜならば、クラスBに、クラスAというサブオブジェクトは、二つあるからだ。p1 != p2を保証するためには、このようなクラスには、standard-layout classになってもらっては困る。
電源ユニットのファンが逝ってしまわれたらしい。急に再起動がかかって何事かと思ったら、電源ユニットが非常に熱くなっていた。GPUをフル稼働させていたのも、原因の一つかもしれない。
電源ユニットは、前のPCのものが余っているのだが、交換するのは面倒だ。ケースを開けて扇風機で風を送るか、GPUをフル稼働させなければ問題ないようだ。
空飛ぶスパゲッティモンスター教(FSM教)では、人体の様々な、不要な部分の持つ真の役割を解説している。
これは預言者Bobby Hendersonによる福音書22ページから24ページにかけての記述に基づくものである。これは単なるセオリーであって、証明されてはいないが、否定されてもいないので、他の証明されていないセオリーである自然科学と対等に扱うべきセオリーである。特に、カンザス州では、全生徒に教育すべきことが望ましい。
自然科学によれば、親知らずとは、まだ我々の祖先が、粗野な食物を食べていたとき、多くの歯ですりつぶす必要があったために存在する歯のことである。
ところで、海賊は、現代人よりよほど粗野な食物を食べていた。また海賊は、喉の奥に剣を隠しておくという離れ業を、こともなくやってのける連中であった。よって、論理的に考えれば、より多くの歯を必要としたはずである。
その他にも、男性の乳首は、海賊が天候や風向きを判断するための計測装置であるし、鳥肌は、海賊が水中で浮力を得るための機能であるし、盲腸の虫垂は、海賊が金貨を隠すための便利な場所である。また、尾骨は、鹿の角と同じく、海賊の戦いのために用いられた。当時の海賊は、お互いに後ろ向きに向かい合い、ケツをふりあげて尾骨を角のように見立てて戦ったらしい。Bobby Hendersonは、この戦闘法を、尻戦(ass-fighting)と命名している。
なお、我々人間は、ビタミンCを合成する遺伝子を持っているが、この遺伝子は働かない。これはなぜかというと、我々の祖先である海賊は、南国にいてフルーツが豊富に得られたため、わざわざ遺伝子を働かす必要がなかったからである。
これらのセオリーは、明確に、我々の祖先が海賊であることをしめしている。当時の海賊は、現代の犯罪集団とは違い、祝福された存在であったのだ。無論、これらのセオリーは証明されたことがないが、否定するに足る証拠も見つかっていない。
もうほとんど痛みはないのだが、傷は治っていない。もう少しで顎を閉じられそうな気がするのだが、まだ痛む。顎の腫れも、まだ残っている。
ほとんど動かせるようになったのに、完全に歯を噛み合わせることができないというのは辛い。
喉の痛みも大方治まったようだ。水が普通に飲める。
しかし、抜歯によって傷付いたのは顎であるはずなのに、なぜ熱が出たり、喉が痛くなったりするのやら。熱はまだしも、喉はよく分からない。
どうもまだ少々の痛みがあるが、これは糸のせいではないかとおもう。
どうも今日は、やけに痛む。抜糸まであと三日。
If you do this in an email, I hate you - The Oatmeal
From: ビル ジマーズ
Subect: 至急、返信を乞う
Attached: UserAgreement.doc (12MB)
こんにちはマットさん。日頃お世話になっております。
さて、本メールに30ページのドキュメントを添付いたしました。
ダウンロードした上で印刷し、署名捺印の上、早急にFAXを願います。
よろしくお願い致します。ビルよりこれは言ってみれば、以下のように言っているのと等しい。
From: 三位の中将ビル、インターネットの雲の上人
Subect: 至急、返り事を送られよかし
Attached: UserAgreement.doc (12MB)
やをれ、マット、確かに承れ。
和殿、必ずスペインまで船の旅にて上りて、これなる羊皮紙に羽ペンにて署名捺印し候へ。
我が都にはインターネットといふもの侍らず。
いやしくも女王より位階を賜わりし身としては、求めに応じて即座に都に上がりて、羊皮紙に署名することぞ、勤めなる。
武運を祈る。三位のビルより。
なんでわざわざ電子メールで紙の署名を求めるんだというお話。果たして、電子メールは紙の手紙に比べて、信頼性が低いのであろうか。例えば、電子メールのサーバーを第三者が運営していれば、確実に変更されない記録は残るはずだ。もちろん、変更することは、メールサーバーの管理者からすれば、技術的に可能であるが、メールを削除する以外のことは、ユーザーからはできない。
結局、何故我々が未だに紙の契約書を作り、はんこを使いたがるかというと、紙の方が歴史があるからにすぎないのだ。言うまでもなく、私は、紙が嫌いである。特に、はんこなどというものは、全く信用していない。はんこの複製は、現代では、ものすごく簡単なのだ。3Dプリンターが発明されてから何年経っていると思っているのか。
そういえば、これに近いことは、私にもたびたびあったような気がする。我々はさらなる文明の進歩のために、紙を捨て去る必要がある。
熱はだいぶ下がったようだ。顎の腫れも、だいぶひいてきた。しかし、相変わらず歯を噛み合わせることができない。喉がまだ少し痛むのが気になる。
おかゆだけでは体に悪いだろうと、豆腐を食べることにした。液体ならば飲めるので、牛乳も買ってみた。そういえば、牛乳を飲むのは久しぶりかもしれない。
もうすこしで治りそうな気もするのだが、どうも痛みが取れない。とにかく、早く抜糸をしたい。
私は、あまり食に関心のない種類の人間である。私に取って食事というのは、生存に必要な栄養を得るための行為であった。私が食に関して気を付けていることは、「同じものを食べ続けない」ということだけである。
ところで、私はつい先日、親知らずを抜いたために、顎が使えず、噛まずに飲み込めるほど薄い粥をすすって生きている。もう三日になるが、これはなかなかに苦行だ。噛みごたえがない食事というのが、こんなに辛いものだとは思わなかった。
私は今まで、美味というものは、主に油と、舌鼻を刺激する物によって決まると思い込んでいた。ところが、実は噛みごたえというファクターがあるらしい。
私は粥に対して、様々な調味料の適用を試みた。しかし、塩を除いては、はかばかしい成功はしなかった。たとえ、ミキサーで焼き肉や焼き魚を粥に混ぜ入れたとしても、あまり良い食べ物にはならないだろう。
しかし、何と言っても私は、まだ粥をすすり始めて三日しか立っていないのだ。しかも希望がある。私の場合、せいぜい一、二週間もすれば、元通り咀嚼できるようになるだろう。それでもなお、粥をすすることにうんざりしている。これは恐るべきことである。世の中には、歯を全部なくしたり、顎を悪くしたりして、まともに咀嚼できない人間が大量にいると聞く。将来、そのような身になりたくはない。
親知らずを抜いて理解したこととは、歯と顎は大切にするべきである。咀嚼力は、スルメを食べる時以外にも発揮しなければならないのだ。
まあしかし、経口摂取できるのは、まだ幸せな方なのかもしれぬ。胃に直接流動食を流し込むよりはマシであろう。点滴は、言うまでもない。
聡明なC++0xプログラマである読者諸君ならば、もう、以下のコードは、C++0xでは、疑いようもなくwell-formedであることを知っているだろう。
// C++03ではill-formed // C++0xではwell-formed vector<vector<int>> v ;
従来、連続した>は、>>演算子と、文法上曖昧であるので、かならず>>演算子だと解釈されるようになっていた。C++0xでは、このような場合、演算子と解釈されることはなくなった。もちろん、分かりやすさから言えば、空白文字を挟んだ方が分かりやすいだろう。
vector< vector< int > > v ;
何にしても、このようなちょっとした落とし穴は、初心者を無用に混乱させる。、C++0xでは、このようなちょっとした落とし穴がいくつも塞がれている。
さて、ここまでが前振りで、ここからが本番である。以下のコードは、C99では、ill-formedである。C++03ではundefined behaviorである。C++0xではwell-formedである。ただし、[EOF]は、ソースファイルの終りを表す。実際の文字ではない。
int main() { }[EOF]
何故か。C99は、空ではないソースファイルは、必ず改行文字で終わらなければならないと定めているからだ。C++03では、空ではないソースファイルが、改行文字で終わっていない場合は、挙動は未定義と定めているからだ。したがって、上記のコードは、C99やC++03といった、前時代の旧言語では、動かない。
しかし、この仕様は、ユーザーの立場になって考えると、馬鹿げている。ソースファイルの終りが改行でなければならないというのは、ユーザー側からすれば、意味が分からない。ユーザー側からすれば、ソースファイルはそこで終わっているのだから。C++0xでは、このような馬鹿げた制限を取り払った。C++0xでは、空ではないソースファイルが、改行文字で終わっていない場合は、改行文字が補われると定めている。したがって、上記のコードは、C++0xという最高にクールな新言語では、well-formedである。
実は、このC++0xの制限緩和は、実に最近の変更である。いつドラフトに入ったのかというと、FCDからである。何と、今年に入ってからの変更だ。
ちなみに、この制限に関する文面は、
C99(TC3)の5.1.1.2 Translation phases paragraph 1.2
C++03の2.1 Phases of translation paragraph 1.2
C++の最新ドラフトN3126の2.2 Phases of translation paragraph 1.2
に書いてある。
親知らずを抜いてから3日目。
やはり熱がある。顎が腫れている。顎を動かすと痛い。
今日も食事はおかゆになるだろう。
顎を動かさなければ、ほとんど痛みはない。しかし、顎を動かさないというのは辛い。物を噛めないし、発声も難しい。また、口を完全にとじることができないというのもつらい。
聞説、親知らずは、問題になる人の割合の方が多いという。しかるに、Web上には、あまり親知らず治療中の情報がない。いつも読んでいるデイリーポータルZに、親知らず治療体験記を発見した。
@nifty:デイリーポータルZ:親知らずの抜歯手術レポート~歯茎の増殖過程を追え!
そこで、ないものは自分で書くことにした。この記事を読んで、まだ親知らずが問題になっていない人は、覚悟できるだろう。
そして
それこそ
『幸福』であるッ!
独りではなく全員が未来を
『覚悟』できるからだッ!
『覚悟した者』は
『幸福』であるッ!
悪い出来事の未来も
知る事は『絶望』と
思うだろうが
逆だッ!
明日『死ぬ』と
わかっていても
『覚悟』があるから
幸福なんだ!
『覚悟』は『絶望』を
吹き飛ばすからだッ!
人類はこれで変わるッ!
これが わたしの求めたものッ!
『メイド・イン・ヘブン』だッ!出典:ジョジョの奇妙な冒険 80巻 メイド・イン・ヘブン その⑨
痛みであまり眠れずに朝を迎える。体調は悪い。明らかに熱があり、体がだるい。右の顎が腫れている。顎が動かせない。喉が痛い。
何か食べなければならない。ここしばらく、一日一食ぐらいしか食べていない。これは、参考書を執筆するのに、集中する必要があるが、満腹では集中できないからだ。したがって、必然的に食事の量は減っていた。そこへきて親知らずだ。私は何も考えずに、土曜日でも、普段行っている歯医者が空いていてよかったと、朝一番、食事もせずに治療に出かけた。思えば、これが失敗だった。何か食べておくべきであった。親知らずを抜いた後は、しばらくまともに物が食べられなくなるのだから。今、おかゆすら食べられなくなっている。
これを読んでいるもので、親知らずの疑いが出てきたものは、まずしっかりと食事をとってから歯医者に行くべきである。少なくとも、抜く前ならば、おかゆぐらいは食べられるであろうから。
それはさておき、このままではまずい。私は一日四回も化膿止めを飲まなければならないのに、何も食べないのは確実にまずい。しかし、おかゆすら食べられないのにどうする。ぼんやりする頭で思案したところ、ウイダーinゼリーが思いついた。あのゼリー状の液体ならば、流しこむことができるのではないか。
さっそく買ってきたところ、どうやら食べられるようだ。
今は、より十倍以上の水でおかゆを作っている。これが食べられるといいのだが。
ちなみに、私の親知らずを抜くのは、だいぶ手間がかかったようだ。一時間以上かかったし、何回も切り分けて取っていたし、歯医者は、「久しぶりやわ、骨とくっついている」などという言葉を漏らしていた。
どうやら、今度は食べられるおかゆを作ることに成功したようだ。野菜などの具が入れられず、なんとも寂しいおかゆだ。卵ぐらいなら入れられるかもしれぬ。
今日、朝起きてみると、どうも口の中がおかしい。何やら、右下の奥の歯肉が、盛り上がっているように思われる。虫歯かと鏡を確認したが、どうもそれらしき歯はない。歯は痛くない。単に腫れているのだろうか。しかし、最近口の中を怪我した覚えはない。
まさか、親知らずだろうか。いやそんなまさか。
ともかく、このままでは食事も満足にできないので、歯医者に行った。歯医者は、口の中を見て一瞬で、レントゲンを取ると言った。現像された写真を見ると、見事に歯が横向きに生えている。親知らずだった。
歯医者「親知らずですねぇ。どうしますか? 抜きますか?」
私「抜く以外の選択はあるんですか?」
歯医者「ありません」
その後、多量の麻酔をかけた後、一時間かけて親知らずを抜いた。そして、口の中を縫った。
そして、帰宅してこれを書いているのだが、徐々に麻酔が切れてきている。だいぶ痛む。やれやれ、親知らずだけはどうにもならん。
ちなみに、左下顎にも、見事に横向に生えている親知らずがあったが、これはまだ問題になっていないので、放置していてもいいらしい。問題にならなければいいのだが。親知らずはもう二度と御免だ。何故あんなに親知らずが忌み嫌われているか、今日はじめて理解した。
追記:麻酔が切れてきた。ものすごく痛む。痛み止めを飲む。実は、まだわずかに血が出ているようだ。
追記2: そろそろ昼飯を食べたいのだが、痛みと出血で食欲が無い。歯医者に行く前に、何か食べておけばよかった。失敗した。
追記3:痛みはだいぶマシになり、出血も治まったようだが、顎を動かすと痛む。また、喉が痛い。何か食べなければならないが、食欲が無い。
Diary Of An x264 Developer » H.264 and VP8 for still image coding: WebP?
H.264のエンコーダー、x264の開発者の一人である、Dark_Shikari氏が、WebPについて語っている。基本的に、WebP規格自体は悪くないのだが、公式のエンコーダーであるlibvpxがクソすぎる。
Dark_Shikari本人曰く、まだ追記するかもしれないとのこと。今は完全に一致しているが、念のためリンク先の翻訳元(英語)を参照することをおすすめする。
JPEGはかなり昔の圧縮フォーマットで、あまりよろしくない。実際のところ、MPEG-2時代の動画フォーマットですら、JPEGには勝てる。なぜ皆が移行しないのかというのは、単純だ。特に利点がないからだ。たとえJPEGより2倍すぐれていたとしても、全世界に対して、20年間使い慣れた画像フォーマットを変更するように強いるのは、不可能だ。さらに、JPEGは高速で、簡単で、事実上、特許やロイヤリティなどがフリーである。JPEGの代替は、かつて何度も試みられた。まず、JPEG-2000、次にMicrosoftのJPEG XR。どちらも、JPEGを王座から引きずり下ろすことを試みた。どちらも、まったく歯が立たなかったのだが。
さて、Googleがまた性懲りもなく新しい画像フォーマットをだしてきたわけだ。"WebP"とかいう、いや待てよ。単なるVP8のイントラフレームじゃないか。この新しい画像フォーマットがJPEGより劣る理由が、すぐに挙げられる。JPEGの全機能をサポートしていないからだ。アルファチャンネル、ロスレスといった機能がサポートされていない。4:2:0 chroma subsamplingしかサポートしていないのだ。JPEGなら4:2:2や4:4:4までもサポートしているというのに。そもそも、Googleはこれらの機能を付け加えることに興味を示していないようである。
まあ、ともかく、これらのエンコーダーが、静止画に対してどれだけ圧縮できるかを試してみよう。すでに説明したように、VP8はH.264とほぼ同じ優秀なイントラ予測(intra prediction)を備えている。すでに説明した理由によって、H.264のイントラ圧縮(intra compression)は、非常に優れているのだ。VP8はi4x4とi16x16モードしかなく、i8x8を持たないので、H.264ほどではないが、ほぼ同じ性能である。
訳注:ここでDark_Shikariが行っているテストとは、H.264とVP8で、1フレームだけエンコードすることによって、静止画圧縮を実現している。これは、H.264とVP8のイントラフレームの性能を比較しているのに等しい。イントラフレームは、単体でデコードできるため、静止画の圧縮フォーマットとしても流用可能である。WebPも、VP8のイントラフーレムを使っているに過ぎない。また、x264とはH.264のエンコーダー、libvpxとはGoogleによるVP8のエンコーダーである。jpgcrushとは、すでにエンコードされたjpegファイル自体を最適化するperlスクリプトである。これは、x264の開発者の一人である、Loren Merrittによって書かれた。最適化はロスレスで行われる。基本的な仕組みとしては、ある状態をjpegフォーマットでコードする方法は複数あり、そのうち最適なものを複数回の試行により選ぶものである。だからロスレスで最適化できる。
テストファイルは、すべて155KB程度である。ダウンロードして確かめるとよい。どのファイルに対しても、私はファイルサイズをほぼ同じにするためのクオリティレベルを。バイナリサーチして弾きだした。x264では、--tune stillimage --preset placeboでエンコードした。livpxでは、--bestでエンコードした。JPEGには、ffmpegを使い、さらにjpgcrushという、ロスレスのjpeg圧縮ツールを用いた。ひょっとしたら、ffmpegより優れたJPEGエンコーダーがあるかもしれない。もし読者が聡明にも、より優れたエンコーダーを知っていたならば、どうぞ自分でも試してもらいたい。画像のソースは、Xiph.org :: Test Mediaによる、Parkjoyの200フーレム目である。
ファイル:x264[154KB]、VP8[155KB]、jpg[156KB]
訳注:このファイルは、H.264とVP8のRaw streamである。このファイルをデコードして見るためには、ffmpegやmplayerなどを使うといい。
訳注:このファイルは、エンコードされたファイルを一度デコードして、PNGに圧縮しなおしたものである。PNGはロスレス圧縮なので、単に画質を目で比較したい場合は、こちらをダウンロードするとよい。
これを見るとどうも、libvpxは赤面ものの結果になっている。主観的に思うに、VP8は最悪である。JPEGはブロッキングノイズがあるとはいえ、VP8よりマシである。何故こうなったのか? VP8には、JPEGよりはるかに優れたエントロピーコーディング(entropy coding)があるというのに。VP8には、より優れたイントラ予測(intra prediction)があるというのに。JPEGにあるのはDC予測(DC prediction)だけだ。なぜVP8がこんなにも劣って見えるのか? 分析してみよう。
VP8は4×4変換(4×4 transform)を使っている。これは一般に、JPEGの8×8変換(8×8 transform)より、ブラーがかかり、細部が失われてしまう。しかし、それだけではここまで酷い違いにはならないはずだ。私の仮説では、おそらく問題は、libvpxの画像のエンコードでは、PSNRに最適化されていて、人間の目とっての高画質を無視しているのだ。ここで、x264を、--tune psnr --preset placeboでエンコードしてみよう、つまり、psy optimizationを無効にするのだ。
訳注:PSNRは、二つの画像を比較して、どのくらい違っているかを図るための、計算方法である。つまり、PSNRを計算することは、エンコードにより画像がどのくらい変化したかという、劣化具合を計算することができる。しかし、PSNRで高得点を得たからといって、必ずしも人間の目にとって、高画質であるとは限らない。x264には、psy optimizationという名称の、より人間的な画質の劣化具合を計算するための比較方法が実装されている。
ファイル:x264、PSNR最適化[154KB]、ちなみに、adaptive quantizationが無効になっているため、ファイルサイズを合わせるために、CQMを使った。
結果(デコードしてPNG圧縮):x264、PSNR最適化
何というブラーだ! VP8より多少はマシなだけである。JPEGより遥かに悪い。これが同じエンコーダーに、同じ品質の解析をさせた結果である。ただ唯一の違いは、psy optimizationを無効にしているだけである。
さて、ここで当然の疑問が沸き起こる。Googleはアホなのか? JPEGより優れているのならば、WebPとやらをプッシュするのも分かる。もちろん、技術的に、ファイルフォーマットとしては、優れている。フォーマットに基づくエンコーダーも、JPEGより優れたものを出力できるであろう。ただし、「できるであろう」ということに注意しなければならない。なぜlibvpxが、未だにクソエンコーダーであるこの時期に発表するんだ? こんなブラーだらけのクソでJPEGを置き換えるというのか?
全世界よりGoogleに告ぐ:まず、てめぇのエンコーダーをまともにしやがれ。代替案として宣伝するのはその後だ。順番が逆ではダメだ。
追記:
maikmertenがtheoraによる比較をしてくれた。PNGとソース。何と、Theora 1.2 (Ptalarbvorm) がVP8を打ち負かしているではないか。生き恥もいいところだな。Ptalarbvormの謳い文句の新機能とは何か。psy optimizationだよ。
ちなみに、以前にも、Dark_Shikari氏と、H.264のイントラフレームを、静止画のフォーマットとして流用することの如何をチャットしたことがある。H.264のイントラフレームを静止画のフォーマットとして使うにあたって、技術的な障害は何もないのだが、やはりすでに普及しているJPEGの牙城を崩すことは難しいだろう。現代では、画像程度のファイルサイズを、あまり気にしないという問題もある。画質はそのままで圧縮率が二倍になったとしても、テラバイトの3.5インチHDDが民生品として売っている現状では、あまり利点はない。
また、WebPは、weppy(ウェッピー)と読むらしい。bが無声音になるらしい。しかもy音が追加される。ふしぎふしぎ。最初、読み方はWeb-Pee(Web小便)かと思った。
追記:Chromium Blog: WebP, a new image format for the Webによれば、将来的にアルファチャンネルをサポートする意思はあるらしい。
本の虫: pixivreaderがすばらしいを書いていて、ふと閃いたことがある。Web上で、画像による広告は逆効果ではないか、ということだ。
Web上では、実に多くの広告を見る。テキスト、画像、動画、音声。甚だしきはFlash。これらの広告は、あまり見たいとは思わない、むしろ邪魔なものである。
ところで、もしFirefoxかChromeを使っているならば、当然、Adblockを使っているだろう。これは、ドメインとCSSセレクターのマッチによって、広告を消し去ってくれる便利なエクステンションである。元はといえば、Firefoxのエクステンションであったが、Chromeにも移植されている。
しかし、このエクステンションは万能ではない。このエクステンションを使ったとしても、多くのWebサイトは、いまだに広告を見せ続ける。これは畢竟、我々があらゆる広告にマッチして、誤爆を一切しないCSSセレクターを書くことができないからである。ちなみに、あらゆるコンテンツにマッチするAdblockのフィルターなら、以下のように記述できる。
##*
冗談はさておき、標準のフィルターでブロックできない広告をブロックしたい場合、自分でフィルターを書かなければならない。これを本格的に行うには、CSSセレクターの知識が必要になる。これは、特に難しいということはないが、少なくとも数分の手間がかかる。CSSセレクターの知識がなくても、最近のAdblockには、大抵クリックした場所を公告とみなして隠す機能があるが、大抵、あまりうまくいかないし、おそらくもっと時間がかかるであろう。
Webサイトをどのように描画するかというとこは、完全にUAの自由であり、広告主は当然、UAはこのような便利な機能を有していることを認識すべきである。
しかし、Adblockのユーザーが、ありとあらゆる広告を隠すことはない。そんなことをしていては、時間の無駄だからだ。Adblockユーザーは、極端に目につく広告だけを隠すはずである。どうも、既存の広告は、目立つということだけを考えていて、Adblockの的になるということは、あまり考えていないようである。
そういう時、どのような広告が目につくのか。
まず、Flashを使っている広告は一発で消されるだろう。もっとも私は、Flash自体を、必要な場合にしか有効にしないので、Flashによる広告を見ることはない。そのようなExtensionがあるからだ。
次に、video要素やaudio要素を使った広告もすぐに消されるだろう。現在のところ、これらの要素を使った広告は、あまり見たことがないが、あのIEですら、IE9でサポートするので、すぐに増えてくるだろう。
上記の広告が消されるのは、当然である。清少納言の言葉を借りれば、すさまじきものだからだ。では、画像はどうか。画像も、否応にも目立つ。広告としては、目立つほどいいのかもしれないが、Web広告に取っては、目立つということは、すなわちAdblockで消されるということである。
では、テキストによる広告はどうか。不思議なことに、私はテキストによる広告をブロックするためにフィルターを書いたことは、ただの一度もない。もちろん、有名所の広告は、すでにAdblock標準のフィルターで消えているというのもあるのであろうが、自分からテキスト広告を消したことはない。すると、テキストによる広告は、一番狙われにくいのではないだろうか。
目立が消される広告と、目立たないが消されない広告、どちらがいいかは自明である。
pixivreader - by edvakf in hatena
これは便利だ。
しかし、こんなextensionを使わなければまともに見ることの出来ないPixivの悲しさよ。まあ、色々な都合があって(見かけ上のPVでも稼ぎたいんだろうか)、わざとああいう使いづらいデザインにしているのだろうが、何とも悲惨だ。
Pixivのデザインの悪さは、意図的なものである。例えば、連中は、広告をわざとNext/Prevの近くに配置することによって、誤クリックによるセコイ広告誘導を狙っている。もちろん、そんな広告は、遠慮無くAdBlockのフィルターを記述して消している。
私はあまり、広告の削除というのはやらないのだ。なぜならば、DOMツリーから該当の要素を見つけ、フィルターを書くには、いくらChromeがすばらしいDOM Inspectorを提供してくれているとはいえ、数分かかる。広告だけに正しくマッチするフィルターのルールを考えなければならないからだ。
それでもやる時というのは、Pixivのように、あまりにも露骨な広告の配置をしている時だけだ。結局、クライアント側が、サイトをどのように描画するかは、クライアント側の意のままであるのだから、サーバー側のこのようなセコイ広告配置は、逆効果である。私のように少しでもCSSをかじっている人間は、容易にAdBlockのフィルターを書く事ができるのだから。
私は、このブログでは、できるだけ本来のコンテンツと広告は、明確に違いがわかるようにしている。何、それでも邪魔だと言うのか? 私も同意する。遠慮無くAdBlockのフィルターを記述して消せばよい。私もそうしている。このようなPV数の低いブログでは、全く儲からないので、そろそろ広告を消すことも考えている。
このように動的に画像を追加する考えを推し進めて、動的に過去の記事を追加するブログというアイディアを思いついたが、それはすでにGoogle Readerがやっているので、わざわざブログ単位でやるまでもないだろう。私は、人のブログは大抵、Google Reader経由で読んでいる。たまに、フィードで全文を配信していないブログがあるが、そういうブログは、大抵読む価値がない(少なくとも、ブログ主はフィードの何たるかを解していないので、価値観が合わない)ので、問題はない。
フィードは、単なる更新を告げるだけであり、全文を含むものではないという思想も、過去にはあったらしいが、フィードリーダーから内容を読むということが一般的になり、また、検索エンジンも、フィードの内容を確認している今となっては、古臭い思想と言わざるをえない。フィードは全文を含むべきである。