「プログラミング言語C++第四版」について気が付いたことなど (5)

意味不明な訳


13.6.4.3 push_back()

…(略)…

あいにく、理にかなった一般的な値は存在しない。vectorを一度push_back()することがあれば、ほぼ間違いなくpush_back()処理が行なわれると想定できる。増加係数の2は、平均的なメモリ利用を最小限に抑える、数学的に最適な係数(1.618)よりも大きいため、メモリが乏しくないシステムであれば、よりよい実行時性能を期待できる。


原文:

As it happens, these are not unreasonable or uncommon values. The assumption is that once we have seen one push_back() for a vector, we will almost certainly see many more. The factor two is larger than the mathematically optimal factor to minimize average memory use (1.618), so as to give beter run-time performance for systems where memories are not tiny.


試訳:

ありがちだが、これらの値は理にかなっていないわけでも一般的でないわけでもない。vectorで一回でもpush_back()が使われれば、もっと沢山使われるのはほぼ確実であろう。増加係数の2は、平均的なメモリ利用を最小限に抑える数学的に最適な係数(1.618)よりも大きいため、メモリが乏しくないシステムであれば、よりよい実行時性能を期待できる。


考察:

not unreasonable or uncommonと二重否定になっているのを見落としていて、マジックナンバーのようだけど実は根拠はあるんだよと言っているのを逆の意味に捉えているように思う。The assumption is の文はどういうわけか many moreを訳していない。

「プログラミング言語C++第四版」について気が付いたことなど (4)

(原書の)コード例の間違い


13.6.4.1 reserve()

template < typename T, typename A >
void vector < T, A >:: reserve( size_ type newalloc) // 欠陥のある最初の版
{
  if (newalloc <= capacity()) return; // 確保分を減らすことはない
  vector < T, A > v( newalloc); // 新しい要素数でvectorを作る
  copy( vb. elem, vb. elem + size(), v. begin());// 全要素をコピー
  vb. space = size();
  swap(∗ this, v); // 新しい値を入れる
} // 古い値を暗黙裏に解放

原書のコード

template < typename T, typename A >
void vector < T, A >:: reserve( size_ type newalloc) // flawed first attempt
{
  if (newalloc <= capacity()) return; // never decrease allocation
  vector < T, A > v( newalloc); // make a vector with the new capacity
  copy( elem, elem + size(), v. begin());// copy elements
  vb. space = size();
  swap(∗ this, v); // install new value
} // implicitly release old value

邦訳でも原書でもvbはvectorの(vector_base型の)メンバ変数として (大分前の §13.6.2 の中ほどのコード例で)宣言されている。vectorがvector_baseから派生していのるであれば原著のようにvb.は要らないが、そうではないのでこれは邦訳の方が正しい

「プログラミング言語C++第四版」について気が付いたことなど (3)

どっちなの?


13. 5. 2   例外 の 捕捉

…(中略)…

原則として、例外は送出時にコピーされる(§13.5)。そのため、例外の保持と転送に対して、処理系はさまざまな方針を適用できる。とはいえ、newが、標準のメモリ不足例外bad_allocを送出するのに必要なメモリがあることは保証されている(§11.2.3)。


と書いてあるので、あれ? と思って §11.2.3 を見てみると、


11.2.3 メモリ領域の割り当て

…(中略)…

どれだけ多くのメモリがあっても、最終的にはbad_allocハンドラが実行される。ここで注意してほしいのは、物理メモリを使い果たすと、new演算子が例外を送出する保証がない、ということだ。


となっている。(太字強調は私)

§13.5.2の原文は

It is guaranteed, howerver, that there is sufficient memory to allow new to throw the standard out-of-memory exception, bad_alloc(§11.2.3)

§11.2.3の原文は

However much memory we have available, this will eventually invoke the bad_alloc handler. Please be careful: the new operator is not guaranteed to throw when you run out of physical main memory.

となっており、訳は間違っていない。

現実的にはbad_alloc例外がthrowされるような事態になることは稀で、なったらなったで適当に落ちてくれれば多くの場合さしたる不都合は無いと思うし、プログラム側で例外処理を書いたとしてもどのみちまともに動かない可能性の方が高いとも思うのだけれども、例外がthrowされる保証があるのか無いのかすっきりしないのは気持ちが悪い。

§13.5.2では「例外をthrowするために必要最低限のメモリはnewの処理として常に残してある」と言っているだけで、だからと言って実際に例外をthrowできるとは限らない、ということなのだろうか?

 

「プログラミング言語C++第四版」について気が付いたことなど (2)

非推奨って言われてもなあ (笑)


13.5.1.3 例外指定

古いC++コードでは、例外指定(exception specification)が使われている。たとえば:

void f( int) throw( Bad, Worse); // 送出する例外は Bad と Worse に限られる
void g( int) throw(); // 例外を送出しない

空の例外指定 throw() は、noexcept(§ 13. 5. 1. 1)と等価である。…(中略)… 空でないthrow 指定子は、使いこなすのが難しい上に、指定された例外が送出されたかどうかの判断のための実行時チェックが高コストになる可能性がある。この機能は、うまくいかなかったので、現在では非推奨とされている。利用し てはいけない。


感想:

これは翻訳の問題ではなくてただの感想ですが、noexcept以外は役に立たないということのようですけれども、標準規格に取り入れられた機能が「うまくいかなかったので非推奨」って言われても困るかも知れません。でも、そもそもユーザー例外って、大域エラー処理以外ではあまり使わないものですし、私はthrow()機能は殆ど使ってないので個人的には実は困りません。

 

「プログラミング言語C++第四版」について気が付いたことなど (1)

分かりにくい訳


12.1.6.1 constexprと参照

constexpr 関数 は、 副作用 が 認め られ て い ない ので、 局所 オブジェクト 以外 の 値 は 変更 でき ない。 その ため、 変更 し ない 限り は、 非 局所オブジェクトを利用できる。


原文:

A constexpr function cannot have side effects, so writing to nonlocal objects is not possible. However, a constexpr function can refer to nonlocal objects as long as it does not write to them.


試訳:

constexpr関数は副作用はもてない。従って非局所オブジェクトに対する書き込み操作は出来ないが、書き込まない限り参照することは出来る。


要するに

割と当たり前のことを言っているのに「そのため」のせいで分かりにくくなっているという … 。

「プログラミング言語C++第四版」について気が付いたことなど (0)

C++98(もう30年も前の規格ですね)で止まっている知識のアップデートをはかるべく「プログラミング言語C++第四版」(ビャーネ・ストラウストラップ著、柴田望洋訳)を読みました。この本はC++11が対象で最新のC++17より6年も前の規格を対象にした本なんですけど、ストラウストラップによる教科書は今のところこれ(4th Edition)が一番新しいですし実用的にはそろそろこの2011年規格が普通に使えるようになってきたくらいなもんじゃないかと思ってますもので、まあ、今齧るにはこの辺りが適当かな、と。この邦訳本が出たのも2015年ですし。

少々古いとは言っても、C++11にはこれまで見たことない書き方やライブラリが沢山追加されていて、一体誰がこんなマニアックな言語仕様やライブラリのサポートを必要としているのだろうと怪訝に思う反面、何も律儀に全機能を使う必要は無いのですし、これまでは制約があって素直に書けなかったところやごちゃごちゃ長々と書くしかなかったところなど、古いやり方にこだわらないで使えるところは柔軟に使っていこうと思います。autoや範囲for文は素直に便利ですし、マルチスレッドのサポートが標準に組み込まれたので(ロックフリープログラミングは難解ですが)マルチプラットフォームなプログラムを書くのが楽になりますし、なにより他人の書いたものが読めないようでは困りますしね。

さて、邦訳は全体的にはスムーズな翻訳だと思います。他の方による初期のエディションの翻訳に比べたらもう雲泥の差ですが、それでも、大部な本ということもあって学生さんの手でも借りたのか監訳者の目が届いていないのか、原文と比べるとどうも怪しいところが幾つかあるように思われます。柴田さんのWEBページに正誤表でもあればと思ったのですけれども、見当たらないので、ならばこの本を読まれる方の参考にでもなればと思い、その辺りを中心に気が付いたことなどメモ代わりに(そっと)書いておこうと思います。

誤解して欲しくないのですが、邦訳は全体的にはスムーズな読み易い訳です。このような良質の日本語の教科書があるのはとても幸せなことです。またもし、指摘の方が間違っているというようなことがあれば、記事にコメントして頂ければ幸いです。

WideStudio Programming (5-2)
~WSCnwbase

本家のクラスライブラリレファレンスによれば WSCnwbase クラスは、

このクラスはウィンドウ資源を持たないクラスの基本となるサブクラスです。このサブクラスを基底とすると、ウィンドウ資源を持たないにもかかわらず、ウィンドウ資源を持つものと同じように振舞うことができます。

ということですが、実際には多くの「これウィンドウ資源持ってるよね」なクラスもここから派生されています。どういう事かというと、 続きを読む WideStudio Programming (5-2)
~WSCnwbase

WideStudio Programming (5-1)
~WSCbase

WSCbaseは、基底クラスを持たないデータ型クラスのようなものを除き、WideStudioで使われるすべてのパーツの基底クラスです。

WSCbase自体が持っている機能で重要なのは、まず何と言っても WSCbase という名前のクラスが存在することです。 続きを読む WideStudio Programming (5-1)
~WSCbase

WideStudio Programming (4-4)
~WM_DROPFILESの処理

さて、ここまでくれば、あとは WM_DROPFILES メッセージを受け取った時の処理を書くだけです。
タンゴレンではドロップされたファイル名をvectorに格納して返すというインターフェースで共通ライブラリ的に使える基底クラスを作って使っています。 続きを読む WideStudio Programming (4-4)
~WM_DROPFILESの処理