シェルスクリプトの中でコマンドが存在するかどうかを確かめる方法

stackoverflow に答えとともに良い説明があった。
http://stackoverflow.com/a/677212/2122085

#!/bin/sh なスクリプトの場合(bash ではなく sh を使っている場合)は

\command -v foo >/dev/null 2>&1 || { echo >&2 "'foo' is required.  Aborting."; exit 1; }

で OK。

こういう場合、よく which を使う(というか僕はいままで which を使っていた)のだけど、それだとどうもコマンドが見つからなかった時に 0(正常終了)を返してくる環境があるらしく、また which は外部コマンドなので多少オーバーヘッドがあったり、ディストリビューションによっては which をカスタマイズしてパッケージマネージャと連携させていたりするらしいのでヘビーデューティなスクリプトだとパフォーマンスに多少影響を与えることになるのかもしれない。

一応上記コマンドの解説。

\command -v は sh のビルトインで、引数で指定されたコマンド(外部コマンド、ビルトインコマンド、エイリアスを含む)を実行はせずに、外部コマンドならそのコマンドの絶対パス、ビルトインコマンドならコマンド名、エイリアスならエイリアスの展開、をそれぞれ表示してくれる。
(stackoverflow の回答では先頭に \ をつけていないけど、念のためつけておくことにした。http://bearmini.hatenablog.com/entry/2013/04/13/000055 参照。)

foo は探したいコマンド。

>/dev/null 2>&1 は command -v の出力を(エラー出力も含めて)捨てている。

|| { 〜 } の部分は、コマンドが見つからなかった時に command ビルトインの終了コードが 0 以外になるので実行される部分。上記の例ではエラーメッセージを表示して exit 1 している。



(sh ではなく)#!/bin/bash を使用している場合は command ビルトインの代わりに type もしくは hash ビルトインが使える。

hash ビルトインを使うと、コマンドをサーチしてその場所がハッシュされて残るので、実際にそのコマンドを実行するときのサーチが高速になるとのこと。ただし外部コマンドを探すときにしか使えず、ビルトインコマンドを探すことができないという欠点がある。

type ビルトインを使うと、2回目以降のサーチが速くなったりはしないがビルトインコマンドも探すことができる。command ビルトインとの違いはよくわからないけど、man を読んだ限りでは、type だと tracked alias というものにも対応しているのかな?ただ、tracked alias の説明をググったりして探してみても ksh というシェルの機能のようで bash では使えなさそう。command -v より type のほうがキータイプ数(ファイルに保存される文字数)が少なくなるというメリットがあるのかな?
上記 stackoverflow の回答では bash のときは hash か type を使えと書いてあるけど command -v ではいけない理由までは書いてないな。

なんかモヤモヤしたままこの記事は終了^^;

GotW #6a: 正しい const 第1部(勝手訳)

GotW #6a の翻訳です。

例によって原文著者(Herb Sutter 氏)の許可は得ていませんし、私の英訳がヒドいクオリティである(用語の統一がとれていないとか、誤訳が含まれているとか)かもしれませんのでそこのところはご理解いただければと思います


原文:http://herbsutter.com/2013/05/24/gotw-6a-const-correctness-part-1-3/

const and mutable have been in C++ for many years. How well do you know what they mean today?

const と mutable は長年にわたって C++ に存在しています。現在それらがどういう意味を持つか、あなたはどのくらい知っていますか?

Problem 問題

JG Question 見習いグルへの問題

1. What is a “shared variable”?

1. "共有変数" とは何か?

Guru Questions グルへの問題

2. What do const and mutable mean on shared variables?

2. 共有変数に対する const と mutable は何を意味するか?

3.How are const and mutable different in C++98 and C++11?

3. const と mutable は C++98 と C++11 においてどのように異なるか?

Solution 解答

1. What is a “shared variable”?

1. "共有変数" とは何か?


A “shared variable” is one that could be accessed from more than one thread at the same time.

"共有変数" は複数のスレッドから同時にアクセスできる変数のことです。


This concept is important in the C++ memory model. For example, the C++ memory model (the core of which is described in ISO C++ §1.10) prohibits the invention of a write to a “potentially shared memory location” that would not have been written to in a sequentially consistent execution of the program, and the C++ standard library refers to this section when it prohibits “modify[ing] objects accessible by [other] threads” through a const function, as we will see in #2.

このコンセプトは C++ メモリモデルにおいて重要です。たとえば、C++ メモリモデル(核となる部分は ISO C++ §1.10 に記述されています)は”潜在的に共有されるメモリ位置" への書き込みを禁じていて、プログラムが正しく実行されている限りにおいてはそのような場所に書き込まれることはありません。また、C++ 標準ライブラリが次の 2. でこれから見るように const 関数によって "[他の] スレッドからアクセス可能なオブジェクトの変更" を禁じているのは、このセクションを参照しているためです。

2. What do const and mutable mean on shared variables?

2. 共有変数に対する const と mutable は何を意味するか?

Starting with C++11, const on a variable that is possibly shared means “read-only or as good as read-only” for the purposes of concurrency. Concurrent const operations on the same object are required to be safe without the calling code doing external synchronization.

C++11 の場合から見て行きましょう。共有される可能性のある変数に対する const は、並列実行の目的のために "読み取り専用 もしくは 読み取り専用と同等" を意味します。同じオブジェクトに対する並列 const 操作は外部的に同期をするためのコードの呼び出しなしで安全であるために必要とされます。

If you are implementing a type, unless you know objects of the type can never be shared (which is generally impossible), this means that each of your const member functions must be either:

あなたが何かの型を実装しようとしているなら、その型のオブジェクトが絶対に共有されることがないとわかっている場合(そんなことは普通ありませんが)を除いて、すべての const メンバ関数は以下のいずれかである必要があることを意味します:

  • truly physically/bitwise const with respect to this object, meaning that they perform no writes to the object’s data; or else
  • internally synchronized so that if it does perform any actual writes to the object’s data, that data is correctly protected with a mutex or equivalent (or if appropriate are atomic<>) so that any possible concurrent const accesses by multiple callers can’t tell the difference.
  • このオブジェクトに関して、真に物理的にビット単位で const である。すなわち、そのオブジェクトのデータに対して書き込みが行われない;もしくは、
  • 内部的に同期しているので実際にはそのオブジェクトのデータに何か書き込んでいるが、そのデータは mutex もしくは同等のもの(もしくは atomic<> が適切ならそれ)を用いて正しく保護されているので、複数の呼び出し元からの何らかの並列な const アクセスにはそれがわからないようになっている。

Types that do not respect this cannot be used with the standard library, which requires that:

これを守らない型は、標準ライブラリと組み合わせて使うことができません。標準ライブラリは以下のことを要求しています:

“… to prevent data races (1.10). … [a] C++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const arguments, including this.”—ISO C++ §17.6.5.9

"... データの競合 (1.10) を防ぐため ... [a] C++ 標準ライブラリ関数は、関数の非 const な引数(this を含む)によって直接または間接的にアクセスされる以外は、直接または間接的に現在のスレッド以外のスレッドからアクセスされるオブジェクト(1.10) を変更してはならない。- ISO C++ §17.6.5.9

Similarly, writing mutable on a member variable means what it has always meant: The variable is “writable but logically const.” Note what this implies:

同様に、メンバ変数に mutable と書くことはすでに述べたような意味を持ちます:その変数は "書き込み可能だが論理的には const" です。これが意味するところは、

  • The “logically const” part now means “can be used safely by multiple concurrent const operations.”
  • The “mutable” and “writable” part further means that some const operations may actually be writers of the shared variable, which means it’s inherently got to be correct to read and write concurrently, so it should be protected with a mutex or similar, or made atomic<>.
  • "論理的に const" の部分は "複数の並列 const 操作によって安全に使うことができる" ということを意味します。
  • "mutable" と "書き込み可能" の部分は、const 操作 によって実際には共有変数に書き込むことがあるかもしれないということを意味し、read と write が同時に行われたとしても本質的に正しくなければならないということであり、mutex もしくは同等のもの、もしくは atomic<> にすることによって保護されるべきであるということです。


In general, remember:

一般的には、以下のルールを覚えてください:

Guideline: Remember the “M&M rule”: For a member variable, mutable and mutex (or atomic) go together.

ガイドライン:"M&M ルール" を覚えましょう:メンバ変数に対して、mutable と mutex (もしくは atomic)はいつも一緒に使います。


This applies in both directions, to wit:

これは両方の面から適用されます。すなわち:

(1) For a member variable, mutable implies mutex (or equivalent): A mutable member variable is presumed to be a mutable shared variable and so must be synchronized internally—protected with a mutex, made atomic, or similar.

(1) メンバ変数に対して、mutable は mutex(もしくは同等のもの)を示唆します:mutable なメンバ変数は mutable な共有変数であると推測されるので、内部的に同期されなければなりません。すなわち mutex を使うかもしくは atomic にするかもしくは同等の方法で保護されなければなりません。

(2) For a member variable, mutex (or similar synchronization type) implies mutable: A member variable that is itself of a synchronization type, such as a mutex or a condition variable, naturally wants to be mutable, because you will want to use it in a non-const way (e.g., take a std::lock_guard) inside concurrent const member functions.

(2) メンバ変数に対して、mutex(もしくは同等の同期型)は mutable を示唆します:mutex や条件変数のような同期型のメンバ変数は、必然的に mutable になるはずです。非 const な方法(たとえば std::lock_guard を取るとか)で並列 const メンバ関数の中から使われるからです。


We’ll see an example of (2) in Part 2, GotW #6b.

(2) の例は第2部、GotW #6b で見て行きましょう。

3. How are const and mutable different in C++98 and C++11?

3. const と mutable は C++98 と C++11 においてどのように異なるか?

First, let’s be clear: C++98 single-threaded code still works. C++11 has excellent C++98 compatibility, and even though the meaning of const has evolved, C++98 single-threaded code that uses the old “logically const” meaning of const is still valid.

まず一つ明確にしておきましょう:C++98 のシングルスレッドのコードは今でも動きます。C++11 は C++98 との素晴らしい互換性を持っていて、const の意味が改良されたにもかかわらず、const をその古い "論理的に const" の意味で使っている C++98 のシングルスレッドのコードは今でも有効です。

With C++98, we taught a generation of C++ developers that “const means logically const, not physically/bitwise const.” That is, in C++98 we taught that const meant only that the observable state of the object (say, via its non-private member functions) should not change as far as the caller could tell, but its internal bits might change in order to update counters and instrumentation and other data not accessible via the type’s public or protected interface.

C++98 では、私たちは C++ 開発者達に "const というのは論理的に const であって物理的/ビット単位で const ということではない" と教えました。すなわち、C++98 においては、cost はそのオブジェクトの観測可能な状態(つまり、private でないメンバ関数を介して、ということですが)が呼び出し元にわかる範囲では変わってはいけないが、内部のビットはカウンタや計測値を更新したり、public もしくは protected なインターフェースを介してアクセスされることのないようなデータは変化しても良いと教えました。

That definition is not sufficient for concurrency. With C++11 and onward, which now includes a concurrency memory model and thread safety specification for the standard library, this is now much simpler: const now really does mean “read-only, or safe to read concurrently”—either truly physically/bitwise const, or internally synchronized so that any actual writes are synchronized with any possible concurrent const accesses so the callers can’t tell the difference.

この定義は並列性のためには不十分です。C++ およびそれ以降では、標準ライブラリのための並列性メモリモデルとスレッド安全性仕様が含まれます。これはよりシンプルです:const は "読み取り専用、もしくは並列読み取りに対し安全" という意味を持つようになりました。これは、真に物理的にビット単位で const であるか、実際には書き込みが同期されていても並列 const アクセス時に呼び出し元に違いがわからないようにするために内部的に同期するかのどちらかです。

Although existing C++98-era types still work just fine in C++98-era single-threaded code for compatibility, those types and any new ones you write today should obey the new stricter requirement if they could be used on multiple threads. The good news is that most existing types already followed that rule, and code that relies on casting away const and/or using mutable data members in single-threaded code has already been generally questionable and relatively rare.

既存の C++98 時代の型は互換性のために今でもちゃんと C++98 時代のシングルスレッドコードで動きます。そのような型も、あなたが今日以降書く新しい型も、もしマルチスレッドで使われるのであれば、新しい厳格な方の要求に従うべきです。良いニュースはほとんどの既存の型は実はそのルールにすでに従っているということです。また、シングルスレッドのコードにおいて、キャストによって cosnt を外してしまうことや mutable なデータメンバを使うことに依存しているようなコードは一般的にはいかがわしいものとされてきましたし、相対的にレアなものです。

Summary まとめ

Don’t shoot yourself (or your fellow programmers) in the foot. Write const-correct code.

自分自身の足を撃ちぬかないでください(もしくは同僚プログラマの足を)。正しい const のコードを書いてください。

Using const consistently is simply necessary for correctly-synchronized code. That by itself is ample reason to be consistently const-correct, but there’s more: It lets you document interfaces and invariants far more effectively than any mere /* I promise not to change this */ comment can accomplish. It’s a powerful part of “design by contract.” It helps the compiler to stop you from accidentally writing bad code. It can even help the compiler generate tighter, faster, smaller code. That being the case, there’s no reason why you shouldn’t use it as much as possible, and every reason why you should.

一貫して const を使うことは正しく同期されるコードのために必要です。それだけでも、一貫して "正しい const" であるべき理由として十分ですが、理由はほかにもあります:正しい const は、インターフェースと不変性について /* これは変更しないよ。約束します! */ なんて書くよりもずっと効率的にドキュメンテーションすることにもなります。これは ”契約によるデザイン (design by contract)" のパワフルな部分です。

Remember that the correct use of mutable is a key part of const-correctness. If your class contains a member that could change even for const objects and operations, make that member mutable and protect it with a mutex or make it atomic. That way, you will be able to write your class’ const member functions easily and correctly, and users of your class will be able to correctly create and use const and non-const objects of your class’ type.

mutable を正しく使うことが "正しい const" のキーになることを覚えておいてください。もしあなたのクラスが const オブジェクトに対する const 操作であっても変更されるようなメンバを持っているなら、そのメンバを mutable にしてそれを mutex で守るか atomic にしてください。そうすると、あなたのクラスの const メンバ関数は簡単に正しく書くことができるようになりますし、あなたのクラスを使う人もあなたのクラス型の const もしくは 非 const オブジェクトを正しく生成して使うことができるようになります。

It’s true that not all commercial libraries’ interfaces are const-correct. That isn’t an excuse for you to write const-incorrect code, though. It is, however, one of the few good excuses to write const_cast, plus a detailed comment nearby grumbling about the library vendor’s laziness and how you’re looking for a replacement product.

すべての商用ライブラリのインターフェースが "正しい const" ではないことは確かです。しかしそれはあなたが "正しくない const" のコードを書くための言い訳にはなりません。ただし、それは const_cast を書くための、そしてそのライブラリのベンダの怠慢やあなたが代わりになる製品を探していることについて愚痴をこぼすための詳細なコメントをそのライブラリのコードの近くに書くための言い訳として許される、数少ないものの一つです。

Acknowledgments 謝辞

Thanks in particular to the following for their feedback to improve this article: mttpd, jlehrer, Chris Vine.

この記事をより良くするための以下の各位からのフィードバックに対し、特に感謝する:mttpd, jlehrer, Chris Vine.

Vagrant で作成した仮想マシンを、ホスト起動時に一緒に自動的に起動する方法(Ubuntu 12.04)

Ubuntu 12.04 の場合、/etc/rc.local あたりに以下のように書いておきます。
(他のバージョンの Ubuntu や、他のディストリビューションでもコマンド自体は同じで大丈夫でしょう。このコマンドを書く場所がちょっと違うかもしれませんが、そのシステムごとに起動時に自動実行されるスクリプトがあるはずですのでそこに書きましょう)

sudo -u $user VBoxManage startvm $vm --type headless

$user は VM を作成した(その VM を管理している)ユーザのユーザ名です。
$vm は VM の名前です。あなたの VM の名前に置き換えてください。
VM の名前がわからないという場合は VBoxManage list vms というコマンドを実行するとたぶんわかります。

GotW #5: 仮想関数のオーバーライド (勝手訳)

GotW #5 の翻訳です。

例によって原文著者(Herb Sutter 氏)の許可は得ていませんし、私の英訳がヒドいクオリティである(用語の統一がとれていないとか、誤訳が含まれているとか)かもしれませんのでそこのところはご理解いただければと思います。


原文:http://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/

Virtual functions are a pretty basic feature, but they occasionally harbor subtleties that trap the unwary. If you can answer questions like this one, then you know virtual functions cold, and you’re less likely to waste a lot of time debugging problems like the ones illustrated below.

仮想関数はとても基本的な機能ですが、ちょっとした引っ掛けをはらんでいます。今回のような問題に答えられるようであれば、あなたは仮想関数について完璧に知っていて、以下で説明されているような問題をデバッグするのに何時間もかけてしまうようなことはないでしょう。

Problem 問題

JG Question 見習いグルへの質問

1. What do the override and final keywords do? Why are they useful?

1. override および final キーワードは何をするか?それらはなぜ有用か?

Guru Question グルへの質問

2. In your travels through the dusty corners of your company’s code archives, you come across the following program fragment written by an unknown programmer. The programmer seems to have been experimenting to see how some C++ features worked.
(a) What could be improved in the code’s correctness or style?
(b) What did the programmer probably expect the program to print, but what is the actual result?

2. あなたはあなたの会社のコードアーカイブの埃をかぶった一角を旅している。あなたは、以下のような誰が書いたかわからないプログラムの断片に行き当たった。そのプログラムを書いたプログラマはいくつかのC++の機能がどのように動くのか、実験していたかのようだ。
(a) コードの正しさやスタイルを改善するとしたら何ができるか?
(b) そのプログラマはこのプログラムが印字することを期待していたのだと思うが、実際には何が起こるか?

class base {
public:
    virtual void f( int );
    virtual void f( double );
    virtual void g( int i = 10 );
};

void base::f( int ) {
    cout << "base::f(int)" << endl;
}

void base::f( double ) {
    cout << "base::f(double)" << endl;
}

void base::g( int i ) {
    cout << i << endl;
}

class derived: public base {
public:
    void f( complex<double> );
    void g( int i = 20 );
};

void derived::f( complex<double> ) {
    cout << "derived::f(complex)" << endl;
}

void derived::g( int i ) {
    cout << "derived::g() " << i << endl;
}

int main() {
    base    b;
    derived d;
    base*   pb = new derived;

    b.f(1.0);
    d.f(1.0);
    pb->f(1.0);

    b.g();
    d.g();
    pb->g();

    delete pb;
}

Solution 解答

1. What do the override and final keywords do? Why are they useful?

1. override および final キーワードは何をするか?それらはなぜ有用か?

These keywords give explicit control over virtual function overriding. Writing override declares the intent to override a base class virtual function. Writing final makes a virtual function no longer overrideable in further-derived classes, or a class no longer permitted to have further-derived classes.

これらのキーワードは、仮想関数のオーバーライドに対して明示的な制御を与えます。override と書くことは、基底クラスの仮想関数をオーバーライドする意図を宣言します。final と書くことは、仮想関数が派生クラスでオーバーライドされないこと、もしくはクラスがそれ以上継承できないようにします。

They are useful because they let the programmer explicitly declare intent in a way the language can enforce at compile time. If you write override but there is no matching base class function, or you write final and a further-derived class tries to implicitly or explicitly override the function anyway, you get a compile-time error.

これらはプログラマに明示的に意図を宣言させ、言語がコンパイル時に強制できるので有用です。あなたが override と書いたのにマッチする基底クラスの関数が存在しなければ、もしくはあなたが final と書いたのに派生クラスで暗黙的もしくは明示的にかかわらず関数をオーバーライドしたら、コンパイル時エラーになります。

Of the two, by far the more commonly useful is override; uses for final are rarer.

これら2つのうち、override のほうが一般的にははるかに有用です。final を使うのはそれに比べると稀です。

2. (a) What could be improved in the code’s correctness or style?

2.(a) コードの正しさやスタイルを改善するとしたら何ができるか?

First, let’s consider some style issues, and one real error:

まず、いくつかあるスタイル上の問題を考えてみましょう。そのうちの一つは実際にエラーです:

1. The code uses explicit new, delete, and an owning *.

1. コードは明示的な new と delete、所有する * を使っている

Avoid using owning raw pointers and explicit new and delete except in rare cases like when you’re writing the internal implementation details of a low-level data structure.

生ポインタを所有したり、new や delete を使うことは避けなければなりません。ただし、低レベルなデータ構造の内部の詳細な実装を書いているというレアケースのような場合は除きます。

{
    base*   pb = new derived;

    ...

    delete pb;
}


Instead of new and base*, use make_unique and unique_ptr.

new と base* の代わりに、make_unique と unique_ptr を使います。

{
    auto pb = unique_ptr<base>{ make_unique<derived>() };

    ...

} // automatic delete here


Guideline: Don’t use explicit new, delete, and owning * pointers, except in rare cases encapsulated inside the implementation of a low-level data structure.

ガイドライン:明示的な new、delete および所有権のある * ポインタを使用しない。低レベルデータ構造の実装の隠蔽された中身のようなレアケースを除く。


However, that delete brings us to another issue unrelated to how we allocate and manage the lifetime of the object, namely:

しかしながら、delete はオブジェクトの確保や生存期間の管理の方法に関係なく、別の問題を持ち込みます。すなわち:

2. base’s destructor should be virtual or protected.

2. base のデストラクタは virtual もしくは protected であるべき。

class base {
public:
    virtual void f( int );
    virtual void f( double );
    virtual void g( int i = 10 );
};


This looks innocuous, but the writer of base forgot to make the destructor either virtual or protected. As it is, deleting via a pointer-to-base without a virtual destructor is evil, pure and simple, and corruption is the best thing you can hope for because the wrong destructor will get called, derived class members won’t be destroyed, and operator delete will be invoked with the wrong object size.

これは無害に見えますが、base を書いた人はデストラクタを virtual にするか protected にすることを忘れています。このまま virtual デストラクタなしで base へのポインタ経由で delete することははっきりいって悪です。こうなるとあなたが望むことのできる最良のものは破滅です。間違ったデストラクタが呼ばれ、derived クラスのメンバが破棄されず、operator delete が間違ったオブジェクトサイズで起動されます。

Guideline: Make base class destructors public and virtual, or protected and nonvirtual.

ガイドライン:基底クラスのデストラクタを public で virtual にするか、protected で 非 virtual にせよ。

Exactly one of the following can be true for a polymorphic type:

ポリモーフィック型において、以下のうちいずれかのみが真となり得ます。

  • Either destruction via a pointer to base is allowed, in which case the function has to be public and had better be virtual;
  • or else it isn’t, in which case the function has to be protected (private is not allowed because the derived destructor must be able to invoke the base destructor) and would naturally also be nonvirtual (when the derived destructor invokes the base destructor, it does so nonvirtually whether declared virtual or not).
  • 基底クラスへのポインタ経由での破棄が許されているならば、デストラクタは public かつ virtual である必要がある;
  • 基底クラスへのポインタ経由での破棄が許されていないのであれば、デストラクタは protected とし(private であってはなりません。派生クラスのデストラクタは基底クラスのデストラクタを起動しなければならないためです)、必然的に非 virtual とします(派生クラスのデストラクタが基底クラスのデストラクタを起動したとき、virtual と宣言されているかどうかにかかわらず、それは非 virtual 的に動作します)。

Interlude 間奏

For the next few points, it’s important to differentiate three terms:

次の点について、3つの用語を区別しておくことは重要です。

  • To overload a function f means to provide another function with the same name in the same scope but with different parameter types. When f is actually called, the compiler will try to pick the best match based on the actual parameters that are supplied.
  • To override a virtual function f means to provide another function with the same name and the same parameter types in a derived class.
  • To hide a function f that exists in an enclosing scope (base class, outer class, or namespace) means to provide another function with the same name in an inner scope (derived class, nested class, or namespace), which will hide the same function name in an enclosing scope.
  • 関数 f をオーバーロードするとは、同じ名前の別の関数を同じスコープ内で異なるパラメータ型で提供するということです。f が実際に呼ばれる時、コンパイラは最もマッチするものを実際に与えられたパラメータにもとづいて選ぼうとします。
  • 仮想関数 f をオーバーライドするとは、派生クラスにおいて同じ名前で同じパラメータ型の別の関数を提供することです。
  • ある包含スコープ(基底クラス、外部クラス、もしくは名前空間)に存在する関数 f を隠すとは、同じ名前で内部スコープ(派生クラス、ネストクラス、もしくは名前空間)に別の関数を提供することです。これは包含スコープの同じ関数名を隠します。

3. derived::f is neither an override nor an overload.

3. derived::f はオーバーライドでもオーバーロードでもない

    void derived::f( complex<double> )


derived does not overload the base::f functions, it hides them. This distinction is very important, because it means that base::f(int) and base::f(double) are not visible in the scope of derived.

derived はいずれの base::f 関数もオーバーロードしません。それらを隠してしまいます。この区別はとても重要です。base::f(int) と base::f(double) は derived のスコープでは不可視となってしまうことを意味するからです。

If the author of derived intended to hide the base functions named f, then this is all right. Usually, however, the hiding is inadvertent and surprising, and the correct way to bring the names into the scope of derived is to write the using-declaration using base::f; inside derived.

derived を書いた人が f という名前の基底クラスの関数を意図して隠したのであればこれは問題ありません。しかし普通は隠すことは意図的ではなく驚きです。derived クラスのスコープにそれらの名前を持ち込むための正しい方法は、derived の中に using 宣言 using base::f; を書くことです。

Guideline: When providing a non-overridden function with the same name as an inherited function, be sure to bring the inherited functions into scope with a using-declaration if you don’t want to hide them.

ガイドライン: 継承された関数と同じ名前で非オーバーライド関数を提供する場合、継承されるはずの関数を隠したくなければ using 宣言を使ってスコープの中にそれらを確実に取り込む。

4. derived::g overrides base::g but doesn’t say “override.”

4. derived::g は base::g をオーバーライドしているが、override と書いていない。

    void g( int i = 20 )  /* override */


This function overrides the base function, so it should say override explicitly. This documents the intent, and lets the compiler tell you if you’re trying to override something that’s not virtual or you got the signature wrong by mistake.

この関数は base の関数をオーバーライドしますので、明示的に override と宣言すべきです。これはその意図をドキュメント化し、あなたが非virtual な何かをオーバーライドしようとしていることや誤って違うシグネチャを書いてしまったことをコンパイラに検出させることができます。

Guideline: Always write override when you intend to override a virtual function.

ガイドライン:仮想関数をオーバーライドしようとしているなら、常に override と書く。

5. derived::g overrides base::g but changes the default argument.

5. derived::g は base::g をオーバーライドしているが、デフォルト引数を変更している。

    void g( int i = 20 )

Changing the default argument is decidedly user-unfriendly. Unless you’re really out to confuse people, don’t change the default arguments of the inherited functions you override. Yes, this is legal C++, and yes, the result is well-defined; and no, don’t do it. Further below, we’ll see just how confusing this can be.

デフォルト引数を変更することは決定的にユーザに不親切です。もしわざと人々を混乱させようとしているのでなければ、オーバーライドする関数のデフォルト引数を変更しないでください。これは C++ 的に合法であり、結果もきちんと定義されています。しかし、絶対にしないでください。この後で、これがいかに混乱を招くかを見ていきます。

Guideline: Never change the default arguments of overridden inherited functions.

ガイドライン:オーバーライドされた関数のデフォルト引数を変更してはならない。

We could go one step further:

さらに一歩推し進めて:

Guideline: Avoid default arguments on virtual functions in general.

ガイドライン:一般に、仮想関数ではデフォルト引数の使用を避ける

Finally, public virtual functions are great when a class is acting as a pure abstract base class (ABC) that only specifies the virtual interface without implementations, like a C# or Java interface does.

最後に、public な仮想関数は、そのクラスが純粋な抽象基底クラス(Abstract base class: ABC)となるときには素晴らしいものです。純粋な抽象基底クラスとは、実装のない仮想インターフェースのみが指定されるもので、C#Java の interface のようなものです。

Guideline: Prefer to have a class contain only public virtual functions, or no public virtual functions (other than the destructor which is special).

ガイドライン: クラスには public な仮想関数だけを持たせる、もしくは public な仮想関数を全く持たせない(デストラクタだけは特別なので除外)のいずれかとせよ。

A pure abstract base class should have only public virtual functions. …

純粋な抽象基底クラスは public な仮想関数だけを持つべきです...

But when a class is both providing virtual functions and their implementations, consider the Non-Virtual Interface pattern (NVI) that makes the public interface and the virtual interface separate and distinct.

しかし、あるクラスが仮想関数とその実装をともに提供するとき、非仮想インターフェース(NVI: Non-Virtual Interface)パターンを考慮してください。public なインターフェースと仮想関数を分離して区別できるようにします。

… For any other base class, prefer making public member functions non-virtual, and virtual member functions non-public; the former should have any default arguments and can be implemented in terms of the latter.

... それ以外の基底クラスは、public なメンバー関数は非 virtual とし、仮想メンバ関数は非 public とします;デフォルト引数は前者にもたせ、また前者は後者を使って実装します。

This cleanly separates the public interface from the derivation interface, lets each follow its natural form best suited for its distinct audience, and avoids having one function exist in tension from doing double duty with two responsibilities. Among other benefits, using NVI will often clarify your class’s design in important ways, including for example that the default arguments which matter to the caller therefore naturally belong on the public interface, not on the virtual interface. Following this pattern means that several classes of potential problems, including this one of virtuals with default arguments, just naturally don’t arise.

これにより public インターフェースを派生インターフェースから明確に分離し、利用者にとってベストで自然な形にすることができますし、一つの関数に2つの責任を負わせて2つの仕事をさせるのを回避することができます。数ある利点の中でも特に、NVI を使うことはあなたのクラスのデザインを重要な点で明確にすることがあります。たとえば呼び出し元にとって問題となるデフォルト引数が仮想インターフェースではなく public インターフェースに自然に属しているといったようなことです。このパターンに従うことで、潜在的な問題となるようなクラス(このデフォルト引数付きの仮想関数をもったものなど)が単純に発生しなくなります。

The C++ standard library follows NVI nearly universally, and other modern OO languages and environments have rediscovered this principle for their own library design guidelines, such as in the .NET Framework Design Guidelines.

C++ 標準ライブラリはほぼすべての箇所で NVI に従っています。また他のモダンな OO 言語や処理系もそのライブラリのデザインガイドラインにおいてこの原則を再発見しています。たとえば .NETのクラスライブラリ設計 開発チーム直伝の設計原則、コーディング標準、パターン (Microsoft.net Development Series)

2. (b) What did the programmer probably expect the program to print, but what is the actual result?

2. (b) そのプログラマはこのプログラムが印字することを期待していたのだと思うが、実際には何が起こるか?

Now that we have those issues out of the way, let’s look at the mainline and see whether it does that the programmer intended:

これまでの問題では本筋から外れてしまっていましたが、いよいよ本流に戻ってそのプログラマが何を意図していたのかを見ていきましょう。

int main() {
    base    b;
    derived d;
    base*   pb = new derived;

    b.f(1.0);

No problem. This first call invokes base::f( double ), as expected.

これは問題ないですね。最初の呼び出しは base::f(double) を期待通り呼び出します。

    d.f(1.0);

This calls derived::f( complex ). Why? Well, remember that derived doesn’t declare using base::f; to bring the base functions named f into scope, and so clearly base::f( int ) and base::f( double ) can’t be called. They are not present in the same scope as derived::f( complex ) so as to participate in overloading.

これは derived::f(complex) を呼び出します。なぜでしょうか?derived が f という名前の base の関数をスコープに持ち込むための using base::f; を宣言していなかったことを思い出してください。ということで、明らかに base::f(int) と base::f(double) は呼び出されません。それらは derived::f(complex) と同じスコープには存在しないので、オーバーロードの対象になりません。

The programmer may have expected this to call base::f( double ), but in this case there won’t even be a compile error because fortunately(?) complex provides an implicit conversion from double, and so the compiler interprets this call to mean derived::f( complex(1.0) ).

そのプログラマは base::f(double) が呼び出されることを期待していたかもしれませんが、このケースでは幸運なことに(?)コンパイルエラーにすらなりません。complex が double からの暗黙の変換を提供していてコンパイラが derived::f(complex(1.0)) を呼び出すように解釈するからです。

    pb->f(1.0);


Interestingly, even though the base* pb is pointing to a derived object, this calls base::f( double ) because overload resolution is done on the static type (here base), not the dynamic type (here derived). You have a base pointer, you get the base interface.

面白いことに、base* pb は derived オブジェクトを指しているにもかかわらず、これは base::f(double) を呼び出します。オーバーロード解決が静的型(ここでは base)に対して行われるからで、動的型(ここでは derived)に対して行われるのではないためです。base ポインタを使うと、base のインターフェースが得られるというわけです。

For the same reason, the call pb->f(complex(1.0)); would not compile, because there is no satisfactory function in the base interface.

同じ理由で、pb->f(complex(1.0)); はコンパイルされません。base インターフェースにおいて、これを満たす関数は存在しないからです。

    b.g();


This prints 10, because it simply invokes base::g( int ) whose parameter defaults to the value 10. No sweat.

これは 10 を出力します。単純に base::g(int) を起動してそのデフォルト引数が 10 だからです。特に面白くありませんね。

    d.g();

This prints derived::g() 20, because it simply invokes derived::g( int ) whose parameter defaults to the value 20. Also no sweat.

これは derived::g() 20 を出力します。単純に derived::g(int) を起動してそのデフォルト引数が 20 だからです。これも特に面白くありません。

    pb->g();


This prints derived::g() 10.

これは derived::g() 10 を出力します。

“Wait a minute!” you might protest. “What’s going on here?” This result may temporarily lock your mental brakes and bring you to a screeching halt until you realize that what the compiler has done is quite proper. (Although, of course, the programmer of derived ought to be taken out into the back parking lot and yelled at.) The thing to remember is that, like overloads, default parameters are taken from the static type (here base) of the object, hence the default value of 10 is taken. However, the function happens to be virtual, and so the function actually called is based on the dynamic type (here derived) of the object. Again, this can be avoided by avoiding default arguments on virtual functions, such as by following NVI and avoiding public virtual functions entirely.

"ちょっと待って!" とあなたは抗議するかもしれません。"いったい何が起こっているの?" この結果は、コンパイラが何をしたのかを正しく理解できるまで一時的にあなたの精神のブレーキをロックしてキキーーッと止まらせてしまうかもしれません。(とはいえ、もちろんその derived を書いたプログラマは裏の駐車場に引きずり出されて怒鳴りつけられるべきでしょうね)覚えておくべきことは、オーバーロードのように、デフォルトパラメータはオブジェクトの静的型(ここでは base)から取られるということで、したがってデフォルト値の 10 が取られます。しかしながら、この関数は virtual として呼び出され、実際に呼び出される関数は動的型(ここでは derived)のオブジェクトにもとづいています。もう一度言いますが、これは NVI に従ったり public な仮想関数を全面的に回避するといったことによってデフォルト引数を仮想関数に与えるのを回避することで回避できます。

    delete pb;
}


Finally, as noted, this shouldn’t be needed because you should be using unique_ptrs which do the cleanup for you, and base should have a virtual destructor so that destruction via any pointer to base is correct.

最後に、すでに述べたように、これは必要とされるべきではありません。unique_ptr を使うべきだからです。unique_ptr があなたのために後片付けをしてくれます。また、base は仮想デストラクタを持つべきです。base への任意のポインタを介してデストラクションが正しく行われるようにするためです。

Acknowledgments 謝辞

Thanks in particular to the following for their feedback to improve this article: litb1, KrzaQ, mttpd.

この記事をより良くするための以下の各位からのフィードバックに対し、特に感謝する:litb1, KrzaQ, mttpd

GotW #4: クラスのメカニクス(勝手訳)

第 4 回めの GotW の翻訳です。

例によって原文著者(Herb Sutter 氏)の許可は得ていませんし、私の英訳がヒドいクオリティである(用語の統一がとれていないとか、誤訳が含まれているとか)かもしれませんのでそこのところはご理解いただければと思います。


原文:http://herbsutter.com/2013/05/20/gotw-4-class-mechanics/


How good are you at the details of writing classes? This item focuses not only on blatant errors, but even more so on professional style. Understanding these principles will help you to design classes that are easier to use and easier to maintain.

あなたはクラスを書くことにどれくらい詳しいですか?この項目では明らかなエラーにフォーカスするだけでなくプロフェッショナルなスタイルについてもフォーカスします。これらの原理を理解することが使いやすく保守しやすいクラスのデザインを助けるでしょう。

Problem 問題

JG Question 見習いグルへの質問

1. What makes interfaces “easy to use correctly, hard to use incorrectly”? Explain.

1. インターフェースを "正しく使うのは容易で、間違って使うのが難しい" ものにするにはどうすればよいですか?説明してください。

Guru Question グルへの質問

2. You are doing a code review. A programmer has written the following class, which shows some poor style and has some real errors. How many can you find, and how would you fix them?

2. あなたはコードレビューをしています。あるプログラマが以下の様なクラスを書きました。いくつか問題のあるスタイルといくつか実際のエラーがあるようです。いくつ見つけられますか?また、どうやって直しますか?

class complex {
public:
    complex( double r, double i = 0 )
        : real(r), imag(i)
    { }

    void operator+ ( complex other ) {
        real = real + other.real;
        imag = imag + other.imag;
    }

    void operator<<( ostream os ) {
        os << "(" << real << "," << imag << ")";
    }

    complex operator++() {
        ++real;
        return *this;
    }

    complex operator++( int ) {
        auto temp = *this;
        ++real;
        return temp;
    }

    // ... 上記を補足するより多くの関数 ...

private:
    double real, imag;
};

Note: This is not intended to be a complete class. For example, if you provide operator++ you would normally also provide operator–. Rather, this is an instructive example to focus on the mechanics of writing correctly the kinds of functions this class is trying to support.

注意:これは完全なクラスであることを意図して書かれていません。たとえば、operator++を提供するなら、普通はoperator-も提供するはずです。それよりも、これはこのクラスがサポートしようとしている機能のようなものを、正しく書くための方式にフォーカスするための手本となるような例です。

Solution 解答

1. What makes interfaces “easy to use correctly, hard to use incorrectly”? Explain.

1. インターフェースを "正しく使うのは容易で、間違って使うのが難しい" ものにするにはどうすればよいですか?説明してください。

We want to enable a “pit of success” where users of our type just naturally fall into good practices—they just naturally write code that is valid, correct, and efficient.

私たちのようなタイプのユーザが書くコードが、有効で、正しくて、効率的なものに自然になるような、"成功のための落とし穴" http://blogs.msdn.com/b/brada/archive/2003/10/02/50420.aspx を可能にしたいと思います。

On the other hand, we want to make it hard for our users to get into trouble—we want code that would be incorrect or inefficient to be invalid (a compile time error if possible) or at least inconvenient and hard to write silently so that we can protect the user from unwelcome surprises.

一方で、私たちのユーザがトラブルに巻き込まれにくくもしたいです。正しくない、または効率的でないようなコードが有効でない(可能であればコンパイル時エラーになる)ように、もしくは、少なくとも黙って書くには不便だったり難しいようにしたいです。そうすることで、ユーザをうれしくないサプライズから守ることができます。


Scott Meyers popularized this guidance. See his concise writeup for further examples.

スコットメイヤーズはこのガイダンスをポピュラーにしました http://programmer.97things.oreilly.com/wiki/index.php/Make_Interfaces_Easy_to_Use_Correctly_and_Hard_to_Use_Incorrectly。彼の簡潔な記事を更なる例として参照してください。

2. You are doing a code review. A programmer has written the following class, which shows some poor style and has some real errors. How many can you find, and how would you fix them?

2. あなたはコードレビューをしています。あるプログラマが以下の様なクラスを書きました。いくつか問題のあるスタイルといくつか実際のエラーがあるようです。いくつ見つけられますか?また、どうやって直しますか?

This class has a lot of problems—even more than I will show explicitly here. The point of this puzzle was primarily to highlight class mechanics (issues like “what is the canonical form of operator<

このクラスはたくさんの問題を抱えています--私がここで明示的に示すよりも多くの問題があります。この問題のポイントは、第一義的にはクラスのメカニクス(operator<<の正しい書き方は?とかoperator+はメンバにするべき?とかいったような問題)を浮き彫りにすることであって、インターフェイスが単にまずくデザインされていることを指摘することではありませんが、まずは二つのおそらくもっとも有用な観察から始めることにしましょう。


First, this is a code review but the developer doesn’t seem to have tried to even unit-test his code, else he would have found some glaring problems.

1つめは、これはコードレビューですが、その開発者はどうやら彼のコードに対してユニットテストさえしていなかったようです。もししていたら、いくつかの明確な問題が見つかっていたはずです。


Second, why write a complex class when one already exists in the standard library? And, what’s more, when the standard one isn’t plagued with any of the following problems and has been crafted based on years of practice by the best people in our industry? Humble thyself and reuse.

2つめに、なぜすでに標準ライブラリに存在している complex クラスを新たに書いたのでしょう?しかも、標準のものは以下の問題には全く悩まされることがなく、業界の最高レベルの人々によって何年分ものプラクティスに基づいて作られているものなのに?謙虚たれ。再利用せよ。


Guideline: Reuse code—especially standard library code—instead of handcrafting your own. It’s faster, easier, and safer.

ガイドライン:コードを再利用せよ -- 特に標準ライブラリのコードを -- 自分で手作りするのではなく。標準ライブラリのコードはより速く、より簡単で、より安全である。


Perhaps the best way to fix the problems in the complex code is to avoid using the class at all, and use the std::complex template instead.

おそらくこの complex コードにおける問題を修正するのにもっとも良い方法は、このクラスを全く使わずに、代わりに std::complex テンプレートを使うことです。


Having said that, it’s an instructive example, so let’s go through the class as written and fix the problems as we go. First, the constructor:

とは言うものの、これは教育的な例なので、このクラスで書かれていることを読んで問題を修正していきましょう。まずはコンストラクタです:


1. The default constructor is missing.

1. デフォルトコンストラクタがない

    complex( double r, double i = 0 )
        : real(r), imag(i)
    { }

Once we supply a user-written constructor, we suppress the implicit generation of the default constructor. Beyond “easy to use correctly,” not having a default constructor makes the class annoying to use at all. In this case, we could either default both parameters, or provide a complex() = default; and declare the data members with initializers such as double real = 0, imag = 0; , or just delegate with complex() : complex(0) { } . Just defaulting the parameter is the simplest here.

ユーザ定義のコンストラクタを提供すると、デフォルトコンストラクタの暗黙的な生成が抑制されます。"正しく使うのが容易" である以前に、デフォルトコンストラクタを持たないことは、そのクラスをまったく使い物にならなくします。このケースでは、両方のパラメータにデフォルトを指定するか、complex() = default; と書いてデータメンバを初期値付きで double real = 0; imag = 0; のように宣言します。もしくは、単に complex(): complex(0) {} とデリゲートしてもよいでしょう。ここでは単にそのパラメータにデフォルトを指定するのが最もシンプルです。

Also, as explained in GotW #1, prefer to use { } consistently for initialization rather than ( ) just as a good modern habit. The two mean exactly the same thing in this case, but { } lets us be more consistent, and could catch a few errors during maintenance, such as typos that would invoke double-to-float narrowing conversions.

また、GotW #1 で説明したように、初期化には () ではなく一貫して {} を使うようにしましょう。これは近代的な良い習慣です。このケースではその2つはまったく同じ意味になりますが、{} のほうがより一貫していますし、保守の時に、double から float へのナローイング変換が起動されてしまうようなタイポなどいくつかの間違いを防ぐことができます。

2. operator+ passes by value.

2. operator+ は値渡し

    void operator+ ( complex other ) {
        real = real + other.real;
        imag = imag + other.imag;
    }

Although we’re about make other changes to this function in a moment, as written this parameter should be passed by const& because all we do is read from it.

この関数にはすぐに別の変更も必要になりますが、この引数からは読み出ししか行わないので const& で渡すべきです。

Guideline: Prefer passing a read-only parameter by const& if you are only going to read from it (not make a copy of it).

ガイドライン:読み取り専用の引数は const& で渡すこと。(コピーが作られない)

3. operator+ modifies this object’s value.

3. operator+ は this オブジェクトの値を変更する

Instead of returning void, operator+ should return a complex containing the sum and not modify this object’s value. Users who write val1 + val2 and see val1 changed are unlikely to be impressed by these gratuitously weird semantics. As Scott Meyers is wont to say, when writing a value type, “do as the ints do” and follow the conventions of the built-in types.

void を返す代わりに、operator+ は合計値を持った complex を返すべきで、this オブジェクトの値を変更するべきではありません。ユーザが val1 + val2 と書いた時に val1 が変更されてしまったとしたら、その不当で奇妙なセマンティクスに感激するということはなさそうです。スコット・メイヤーズがよく言うように、値型を書くときは、"int がするようにする"、そして組込み型の変換に従うことです。

4. operator+ is not written in terms of operator+= (which is missing).

4. operator+ は operator+= を使って書かれていない(そして operator+= は存在するべきなのに欠けている)

Really, this operator+ is trying to be operator+=. It should be split into an actual operator+ and operator+=, with the former calling the latter.

実際のところ、この operator+ は operator+= になろうとしています。これは operator+ と operator+= に分けられるべきで、前者が後者を呼び出すようにすべきです。

Guideline: If you supply a standalone version of an operator (e.g., operator+), always supply an assignment version of the same operator (e.g., operator+=) and prefer implementing the former in terms of the latter. Also, always preserve the natural relationship between op and op= (where op stands for any operator).

ガイドライン:ある演算子の単独のバージョン(たとえば operator+)を提供するなら、常にその演算子の代入バージョン(たとえば operator+=)も提供し、前者を実装するのに後者を使用するようにする。また、op と op= の間の自然な関係を常に維持する(op は任意の演算子)。


Having += is good, because users should prefer using it. Even in the above code, real = real + other.real; should be real += other.real; and similarly for the second line.

+= を持つことはいいことです。ユーザがそれを優先的に使用することができるからです。上記のコードでも、real = real + other.real; は real += other.real; となるべきです。2行目も同様です。


Guideline: Prefer writing a op= b instead of a = a op b (where op stands for any operator). It’s clearer, and it’s often more efficient.

ガイドライン:a = a op b ではなく、a op= b を優先すること(ここで op は任意の演算子を表す)。より明快で、しばしばより効率的である。


The reason why operator+= is more efficient is that it operates on the left-hand object directly and returns only a reference, not a temporary object. On the other hand, operator+ must return a temporary object. To see why, consider the following canonical forms for how operator+= and operator+ should normally be implemented for some type T.

operato+= がより効率的である理由は、それが左辺のオブジェクトに直接作用し、一時オブジェクトではなく参照を返すからです。かたや operator+ は一時オブジェクトを返さなければなりません。理由を見るために、以下の正規化された形式の operator+= と operator+ がある型 T に対して通常どのように実装されるべきかを考えてみましょう。

T& T::operator+=( const T& other ) {
    //...
    return *this;
}

T operator+( T a, const T& b ) {
    a += b;
    return a;
}


Did you notice that one parameter is passed by value, and one by reference? That’s because if you’re going to copy from a parameter anyway, it’s often better to pass it by value, which will naturally enable a move operation if the caller passes a temporary object such as in expressions like (val1 * val2) + val3. This is a good habit to follow even in cases like complex where a move is the same cost as a copy, since it doesn’t cost any efficiency when move and copy are the same, and arguably makes for cleaner code than passing by reference and adding an extra named local object. We’ll see more on parameter passing in a future GotW.

ひとつの引数が値で渡され、もう一つが参照で渡されていることに気づきましたか?どのみち引数からコピーするのであれば最初から値で渡してしまったほうがよいですし、値で渡されると呼び出し元が一時オブジェクトを渡した時にムーブ操作が可能となります。たとえば式 (val1 * val2) + val3 のときのように。これは complex のようにムーブがコピーと同じコストであるようなケースでも従うべき良い習慣です。なぜならムーブとコピーが同じだったとしても効率性を犠牲にすることはありませんし、参照で渡して余計なローカルな名前付きオブジェクトを追加するよりもほぼ間違いなくクリーンなコードになるからです。将来の GotW でパラメータ渡しについてより詳しく見ていきます。


Guideline: Prefer passing a read-only parameter by value if you’re going to make a copy of the parameter anyway, because it enables move from rvalue arguments.

ガイドライン:どのみちパラメータのコピーを作るのであれば、読み取り専用パラメータを値で渡すようにする。rvalue 引数からムーブが可能となるので。


Implementing + in terms of += both makes the code simpler and guarantees consistent semantics as the two functions are less likely to diverge during maintenance.

+ を += を使って実装することは、コードをよりシンプルにしますし、保守の間に2つの関数が枝分かれしにくく一貫したセマンティクスを保証します。

5. operator+ should not be a member function.

5. operator+ はメンバ関数であるべきではない

If operator+ is made a member function, as it is here, then it won’t work as naturally as your users may expect when you do decide to allow implicit conversions from other types. Here, an implicit conversion from double to complex makes sense, but with the original class users have an asymmetry: Specifically, when adding complex objects to numeric values, you can write a = b + 1.0 but not a = 1.0 + b because a member operator+ requires a complex (and not a double) as its left-hand argument.

ここに書かれたように operator+ がメンバ関数であるならば、他の型からの暗黙の変換を可能にしようと決めた時にユーザが期待するとおりに自然には動かなくなります。ここでは、double から complex への暗黙の変換は意味がありますが、オリジナルのクラスのユーザは非対称性を持つことになります:特に、complex オブジェクトを数値に足すとき、 a = b + 1.0 とは書けるのに、a = 1.0 + b とは書けません。メンバ operator+ は左側の引数に complex (double ではない)を必要とするからです。


Finally, the other reason to prefer non-members is because they provide better encapsulation, as pointed out by Scott Meyers.

最後に、非メンバを使うべきもう一つの理由は、スコット・メイヤーズが指摘(http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197)するように、それがよりよいカプセル化を提供するからです。


Guideline: Prefer these guidelines for making an operator a member vs. nonmember function: unary operators are members; = () [] and -> must be members; the assignment operators (+= –= /= *= etc.) must be members; all other binary operators are nonmembers.

ガイドライン:演算子をメンバ関数にするか非メンバ関数にするかという問題に対し、以下のガイドラインを用いる:単項演算子はメンバにする。= () [] -> はメンバでなければならない。代入演算子(+= -= /= *= など)はメンバでなければならない。他のすべての二項演算子は非メンバ。

6. operator<< should not be a member function.

6. operator<< はメンバ関数であるべきではない

The author of this code didn’t really mean to enable the syntax my_complex << cout, did they?

このコードを書いた人は、シンタックス my_complex << cout を可能にしたかったわけではないですよね?

    void operator<<( ostream os ) {
        os << "(" << real << "," << imag << ")";
    }


The same reasons already given to show why operator+ should be a nonmember apply also to operator<<, only more so because a member the first parameter has to be a stream, not a complex. Further, the parameters should be references: (ostream&, const complex &).

operator+ が非メンバであるべきであることを示すのにすでに与えられたのと同じ理由が operator<< にも適用されます。それだけではなく、メンバなのであれば最初のパラメータは complex ではなく stream であるべきです。さらに、パラメータは参照であるべきです:(ostream&, const complex&)


Note also that the nonmember operator<< should normally be implemented in terms of a(n often virtual) const member function that does the work, usually named something like print.

非メンバ operator<< は通常、実際の仕事をするconst メンバ関数(virtual にすることが多く、たいてい print のような名前)を使って実装されるべきです。

7. operator<< should return ostream&.

7. operator<< は ostream& を返すべき

Further, operator<< should have a return type of ostream& and should return a reference to the stream in order to permit chaining. That way, users can use your operator<< naturally in code like cout << a << b;.

さらに、operator<< は返り値の型として ostream& を持つべきで、チェイン化を可能とするために引数として渡された stream への参照を返すべきです。こうすることで、ユーザは cout << a << b; のようなコードの中であなたの operator<< を自然に使うことができます。


Guideline: Always return stream references from operator<< and operator>>.

ガイドライン:operator<< と operator>> からは常に stream の参照を返す。

8. The preincrement operator’s return type is incorrect.

8. 前置インクリメント演算子の返り値の型が正しくない

    complex operator++() {
        ++real;
        return *this;
    }


Ignoring for the sake of argument whether preincrement is meaningful for complex numbers, if the function exists it should return a reference. This lets client code operate more intuitively and avoids needless inefficiency.

前置インクリメントが complex (複素数)に対して意味のあるものかどうかという議論はさておき、前置インクリメントの関数が存在するのであればそれは参照を返すべきです。これはクライアントコードをより直感的に作用させ、無意味な非効率性を回避させます。


Guideline: When you return *this, the return type should usually be a reference.

ガイドライン:return *this と書くときは返り値の型は通常は参照です。

9. Postincrement should be implemented in terms of preincrement.

9. 後置インクリメントは前置インクリメントを使って実装されるべき

    complex operator++( int ) {
        auto temp = *this;
        ++real;
        return temp;
    }


Instead of repeating the work, prefer to call ++*this. See GotW #2 for the full canonical form for postincrement.

作業を繰り返すのではなくて、++*this を呼び出すようにしましょう。後置インクリメントの完全な正規形は GotW #2 を見てください。


Guideline: For consistency, always implement postincrement in terms of preincrement, otherwise your users will get surprising (and often unpleasant) results.

ガイドライン:一貫性のために、後置インクリメントは常に前置インクリメントを使って実装します。さもなければユーザは驚くような(そしてそれはたいてい嬉しくない)結果を得ることになります。

Summary まとめ

That’s it. There are other modern C++ features we could apply here, but they would be arguably gratuitous and not appropriate for general recommendations. For example, this is a value type not designed to be inherited from, so we could prevent inheritance by making the class final, but that would be protecting against Machiavelli, not Murphy, and there’s no need for a general guideline that tells everyone they should now write final on every value type; that would just be tedious and unnecessary.

以上です。他にも適用可能なモダンな C++ の機能がありますが、それはほぼ間違いなく余計なもので、一般的な推奨としては適切ではないでしょう。たとえば、これが値型であって継承されるようにデザインされていないので、クラスを final にすることで継承を防ぐことができます。しかしそれはマキアヴェッリから守るかもしれませんがマーフィーからは守りません(訳注:マキアヴェッリは目的のために手段を選ばない様から、重箱の隅をつつくような、ごく希な間違い・失敗のことを表していると考えられ、マーフィーはマーフィーの法則から、人々が起こしがちなよくある間違いのことを表していると考えられます)。そして全員に今すぐすべての値型に対して final と書けと命じるような一般的なガイドラインの必要性もありません;単につまらない不必要なものになりかねません。


Here’s a corrected version of the class, ignoring design and style issues not explicitly noted above:

最後に修正されたバージョンのクラスを示します。ここでは上記で明示的に示された設計やスタイル上の問題は無視しています:

class complex {
public:
    complex( double r = 0, double i = 0 )
        : real{r}, imag{i}
    { }

    complex& operator+=( const complex& other ) {
        real += other.real;
        imag += other.imag;
        return *this;
    }

    complex& operator++() {
        ++real;
        return *this;
    }

    complex operator++( int ) {
        auto temp = *this;
        ++*this;
        return temp;
    }

    ostream& print( ostream& os ) const {
        return os << "(" << real << "," << imag << ")";
    }

private:
    double real, imag;
};

complex operator+( complex lhs, const complex& rhs ) {
    lhs += rhs;
    return lhs;
}

ostream& operator<<( ostream& os, const complex& c ) {
    return c.print(os);
}

Acknowledgments 謝辞

Thanks in particular to the following for their feedback to improve this article: Mikhail Belyaev, jlehrer, Olaf van der Spek, Marshall, litb1, hm, Dave Harris, nosenseetal.

この記事をより良くするための以下の各位からのフィードバックに対し、特に感謝する: Mikhail Belyaev, jlehrer, Olaf van der Spek, Marshall, litb1, hm, Dave Harris, nosenseetal.

Xmodmap でお好みのキーバインド

前フリ

プログラマのみなさんならキーボードにこだわりを持ってなおかつタイピング速度を0.01秒でも稼ぐために日夜キーバインドを研究されていることと思います。

そんな私は Windows では AutoHotKeyLinux では Xmodmap、Mac では KeyRemap4Mac を愛用しております。

新しい環境や新しいキーボードが手に入ったりするとまずはキーボードの設定から、という方も多いのではないでしょうか。

私は HHK を長年愛用しており、新しいコンピュータを購入したら何はともあれコイツをつないで、キーバインドの設定からはじめます。

とはいえ、もう長いこと使い込んだ設定ファイルの類はそんなに直す機会はないのですが、近頃 RealForce のお下がりをもらったのでこれをもう少し使いこんでみようとしておりまして、久しぶりに設定ファイルを書くハメになったわけです。

このキーボードを Linux で使うことにしたので、Xmodmap の設定ファイルを新たに作る必要があります。

しかし Xmodmap の書き方をすっかり忘れてしまっていたのでメモしておきます。
(どうも Web 上に転がってる情報は古いのが多いのか、設定ファイルのフォーマットとかも最近のものとは異なるようですし、統一的な情報がまとめられたページが日本語/英語ともに見当たりませんでしたので。もしかしてキーバインドを変更するような人ってもはやオールドタイプというか生きた化石というか obsoleted で deprecated な存在!?)


キーバインドの設定の大まかな流れは以下のようになります。

  1. xev コマンドで、どのキーを押したらどのようなキーコードがキーボードから送られてくるかをチェック
  2. キーコードがわかったら .Xmodmap ファイルにキーバインドを記述


私は HHK では左◇キーと h, j, k, l をそれぞれ同時に押したらそれがカーソルキーになるといったキーバインドを設定していますので、RealForce でも同様なキーバインドができるようになることを想定しています。

それ以上複雑なことはしようとは今のところ考えていません。


それでは、さっそく始めましょう。


1. xev コマンドで、どのキーを押したらどのようなキーコードがキーボードから送られてくるかをチェック

まず、おもむろにターミナルから xev コマンドを実行します。
すると、Event Tester という白いウインドウが出てくると思います。
同時に、ターミナルにはいろいろなイベントの情報がずらずらと表示されると思います。

Event Tester にフォーカスを合わせ、何かキーを押してみましょう。

たくさんの情報が表示されると思いますが、そのなかから KeyPress イベントや KeyRelease イベントを探しましょう。

KeyPress event, serial 36, synthetic NO, window 0x4200001,
    root 0xb6, subw 0x0, time 30146314, (1536,-767), root:(1602,494),
    state 0x0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 36, synthetic NO, window 0x4200001,
    root 0xb6, subw 0x0, time 30146434, (1536,-767), root:(1602,494),
    state 0x8, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

それぞれ 3 行目くらいに
keycode 64 (keysym 0xffe9, Alt_L)
っていうのが見えると思います。

これは私の持っているキーボードで左 Alt キーを押した時の例です。

目的の数字は 64 です。
他のキーを押すとここが別の値になっていると思います。
また、同じ左 Alt キーでも、環境が異なれば別の値になっているかもしれません。


以下のコマンドを実行すると、現在割り当てられているキーバインドの一覧を確認することができます。

$ xmodmap -pke 


キーバインドを設定したいキーをいろいろ押してみたり、上記の一覧を参照しながら、そのキーコードをメモしておきましょう。

私の場合は、HHK で ◇ キーに相当する位置に RealForce では左 Alt キーがありますので、左 Alt + H, J, K, L でカーソルキーが押されたかのようにしたいと思います。
そこで、左 Alt キー と H, J, K, L の各キーのキーコードを調べます。

また、Alt + H などを入力したときにカーソルキーとして動くようになってしまうと、本当に Alt + H を入力したいときにできなくなってしまいますので、Windows キーを潰して代わりにそれを Alt キーのように使いたいと思います。

つまり、左 Alt キー を ◇ キーのようなキーに変更し、Windows キーを新しい左 Alt キーに変更します。
ついでに Caps Lock は不要なので Control キーに変更してみたいと思います。

キーボード上の物理的なキー キーコード 新しい役割
左 Alt 64 HHK の ◇ キーのようなキー
Windows 133 左 Alt
Caps Lock 66 左 Control
H 43 ◇+H でカーソルの左キー
J 44 ◇+J でカーソルの下キー
K 45 ◇+K でカーソルの上キー
L 46 ◇+L でカーソルの右キー

なお、上記のキーコードは私の環境でそうだったというだけで、環境が異なれば値も異なります。


調べ終わったら、xev のウインドウを閉じます。


2. キーコードがわかったら .Xmodmap ファイルにキーバインドを記述

さて、キーコードがわかったら、~/.Xmodmap ファイルを開いて編集しましょう。

ポインタ(マウス)の設定

Ubuntu 12.04 もしくは類似の環境の場合、デフォルトでは、次のような内容のファイルが存在しているかもしれません。存在していなければこのセクションは無視してください。

pointer = 1 2 3 4 5 6 7 8 9 10 11 12

これの意味するところは、マウスのボタンの入れ替え設定です。

とはいえ、上記の設定ではボタンの入れ替えはしていません。つまり、
物理的に 1 番のボタンが押されたらボタンコード 1 番が生成されて、
物理的に 2 番のボタンが押されたらボタンコード 2 番が生成されて、
 :
物理的に 12番のボタンが押されたらボタンコード 12番が生成されるように設定されています。

pointer = のあとに、物理ボタンの番号順に、生成したいボタンコードをスペースで区切って書いていきます。

ちなみに、普通のマウスでは 1 番のボタンとは左ボタン、2番のボタンが中ボタン、3番のボタンが右ボタンと割り当てられているようです。また、ホイールを上向きに回すと4番のボタンが押されたかのようにコードが生成され、下向きに回すと5番のボタンが押されたとみなされるようです。私の環境でもそうなっていました。

普通の人が持っているマウスはせいぜいその 5 つくらいのボタンを持っていると思いますが、Xmodmap の設定ファイルではもっとたくさんのボタンを持っているマウスのために、デフォルトで12個のボタンの定義が書かれているのだと思います。

もし、左ボタンと右ボタンの役割を入れ替えたいのであれば、

pointer = 3 2 1 4 5 6 7 8 9 10 11 12

と記述すれば良いようです。

こうすると、物理的に1番のボタン(左)が押されるとボタンコード3番(右)が生成され、物理的に3番(右)のボタンからはボタンコード1番(左)が生成されます。

また、4 と 5 を入れ替えると Natural Scrolling のような事ができるかもしれません。

マウスのボタンの入れ替えを考えていないのであれば、この行は元のまま残しておきましょう。

キーコードと keysym

さて、話がそれました。キーバインドの設定をしましょう。


以下のコマンドを実行すると、現在割り当てられているキーバインドの一覧を確認することができるのでした。

$ xmodmap -pke 


たとえば A キーの割り当ては、

keycode  38 = a A a A

となっていました。

これの意味するところは、右辺の左から順番に

  • A キーだけを押したら小文字の a
  • Shift + A を押したら大文字の A
  • Mode_switch + A を押したら小文字の a
  • Mode_switch + Shift + A を押したら大文字の A

が入力されるということです。

さて、ここで Mode_swtich とはなんでしょう?
聞いたことのないキーです。

$ xmodmap -pke | grep -i mode_switch

と実行すると、私の環境では

keycode 203 = Mode_switch NoSymbol Mode_switch

となっていました。

しかし、私のキーボード上のどのキーを押しても、このキーコードを発生させることができませんでした。

キーボードによっては、このキーコードを発生させる AltGr というキーを持っているものもあるそうですが、私のキーボードにはそのような物理的なキーはありません。

それでは、左 Alt キーを Mode_switch のように働かせて、Mode_switch + H, J, K, L の役割をカーソルキーの上下左右に割り当てれば良さそうです。

まず物理的な左 Alt キー(私の環境ではキーコードは 64 でした)を Mode_switch キーに変更するには、.Xmodmap ファイルに以下の行を書きます。

keycode 64 = Mode_switch

これで、キーコード 64 のキー(物理的な左 Alt キー)に Mode_switch という役割を割り当てたことになります。ちなみに、この、右辺に書かれているキーの役割のことを keysym と言います。

キーコードの数字は、私は10進数で書きましたが、16進数などで書いても良いようです。
keysym は大文字小文字を区別します。Mode_switch の s は小文字ですので気をつけてください。

他にどのような keysym があるかは /usr/include/X11/keysymdef.h というファイルの中に記述されています。(XK_ というプリフィクスを取り除いたものが keysym になります。)
なお、このファイルは x11proto-core-dev というパッケージをインストールしておかないと存在しません。


さて、これだけで済めば良いのですが、実はそうもいきません。

キーコード 64 のキーは元々 Alt_L という keysym を持っていて、そのキーコード 64 のキーはモディファイアキーという特殊なキーに割り当てられていますので、上記の行だけではまだ足りないのです。
(モディファイアキーに割り当てられていないキーは上記の行だけで設定変更が可能)


モディファイアキー

モディファイアキーとは、Control や Shift、Alt などのように、他のキーと組み合わせて使うためのキーです。

あなたの環境でどのようなモディファイアキーが定義されているかは以下のように単に xmodmap コマンドを実行することで知ることができます。

$ xmodmap
xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3      
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

上記は私の環境でのデフォルトの例です。

例えば shift というモディファイアキーの役割を実行するには、キーコード 0x32 のキー(Shift_L という役割を与えられているが物理的に左シフトキーとは限らない)かキーコード 0x3e のキー(Shift_R という役割を与えられているが物理的に右シフトキーとは限らない)を押せば良いということを表しています。

キーコード 0x40 のキー(0x40 は 10 進数で 64 なので、上記調査結果からこれは物理的な左 Alt キーです)を押すと、mod1 というモディファイアキーになるようです。

shift、lock、control についてはなんとなくどんな役割か想像がつきますが、mod1〜mod5 のモディファイアキーについてはなんだかよくわかりませんね。
普通に生活している分には mod1〜mod5 のモディファイアにはお世話にならない気がしますので、気にしないでおきましょう。

さて、モディファイアキーに割り当てられている keycode に、別の keysym を割り当てるときは、一旦モディファイアキーのグループから抜けさせないといけない、というルールがあるようです。

私の例では左 Alt キー(キーコード 64)は mod1 のグループに入れられていますので、別の keysym(役割)を割り当てるまえに、このグループから抜けさせないといけません。

そこで、先ほどの .Xmodmap の設定ファイルの先頭に以下の行を追加します。

! この行を追加
remove mod1 = Alt_L

! これはさきほど書いておいた行
keycode 64 = Mode_switch

(行の先頭に ! がある行はコメントとみなされます。)

remove mod1 = Alt_L という書き方はなんとなく気持ち悪いですが、mod1 というグループから Alt_L を削除するという意味です。

これで、物理的に左 Alt キーを押すと Mode_switch キーとして働くようになります。

.Xmodmap ファイルを保存したら、以下のコマンドで読み込んでみましょう。

$ xmodmap ~/.Xmodmap

エラーは起こらなかったでしょうか?
大丈夫なようなら xev コマンドを起動し、物理的な左 Alt キーを押した時の keysym がどうなったか見てみましょう。

KeyPress event, serial 36, synthetic NO, window 0x1c00001,
    root 0xb6, subw 0x0, time 148526330, (1151,-215), root:(1201,557),
    state 0x0, keycode 64 (keysym 0xff7e, Mode_switch), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 36, synthetic NO, window 0x1c00001,
    root 0xb6, subw 0x0, time 148526458, (1151,-215), root:(1201,557),
    state 0x0, keycode 64 (keysym 0xff7e, Mode_switch), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

keysym が Mode_switch になっていますね。やりました!

$ xmodmap
xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3      
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

mod1 から Alt_L (0x40) が抜かれていますね。


それでは、ようやく目的の H, J, K, L との組み合わせを .Xmodmap に記述していきましょう。

remove mod1 = Alt_L
keycode 64 = Mode_switch

! ここから下を追加
keycode 43 = h H Left Left
keycode 44 = j J Down Down
keycode 45 = k K Up Up
keycode 46 = l L Right Right


保存したら、また同じコマンドで .Xmodmap を読み込ませてみます。

$ xmodmap ~/.Xmodmap


左 Alt + H, J, K, L で上下左右にカーソルが動いたら成功です!


あとは残りの Windows キーと Caps Lock キーの変更を行いましょう。
私の環境では、Windows キーはキーコード 133 で、Super_L という keysym を持っていました。また、mod4 というモディファイアキーのグループに入っていました。

Caps Lock キーはキーコード 66 で、Caps_Lock という keysym を持っており、lock というモディファイアキーのグループに入っています。

したがって、キーコード 133(Windows キー)やキーコード 66(Caps Lock キー)に別の役割(keysym)を割り当てるために、それぞれモディファイアキーのグループから一旦抜けさせないといけません。

また、Caps Lock キーは Control キーとして生まれ変わるために、keysym を割り当てたあとに control モディファイアキーのグループに仲間入りさせてあげないといけません。

これらを総合すると、.Xmodmap ファイルは以下のようになるでしょう。

remove mod1 = Alt_L
remove mod4 = Super_L
remove lock = Caps_Lock

keycode 64 = Mode_switch
keycode 133 = Alt_L
keycode 66 = Control_L

keycode 43 = h H Left Left
keycode 44 = j J Down Down
keycode 45 = k K Up Up
keycode 46 = l L Right Right

add control = Control_L

一般的に、.Xmodmap ファイルの中身は以下の順番で記述すると良いようです。


  1. モディファイアキーのグループから remove
    (役割を変更したい keycode にその時点で割り当てられている keysym を remove)

  2. keycode に keysym を割り当てる
    (物理キーに役割を割り当てる)

  3. モディファイアキーのグループに add
    (新しく割り当てられた役割に応じてモディファイアキーとして動作するように再割当て)



この .Xmodmap を読み込ませたあとのモディファイアキーの割り当ては以下のようになっています。

$ xmodmap
xmodmap:  up to 3 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock      
control     Control_L (0x25),  Control_L (0x42),  Control_R (0x69)
mod1        Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3      
mod4        Super_R (0x86),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

lock グループに割り当てられているキーはなくなりました。
これでどんなキーを押しても Caps Lock として働くことはなくなったということです。

代わりに、キーコード 0x42(66)の Control_L が control グループに仲間入りしています。
元々あった左 Control キーに加え、Caps Lock キーもコントロールキーとして働くようになったということです。

また、Super_L もなくなりました。新しく割り当てた Mode_switch もどこにも入っていません。
これらのキーをモディファイアキーとして使いたければ、add を使って mod4 とか mod5 に追加してあげるとよいかもしれません。(私はいずれにしろ mod1〜mod5 は使いませんのであえて add しませんでした)

これで .Xmodmap で設定できることはだいたい説明し終わったはずです。
ここまでのことが理解できていれば、あとは man xmodmap でも見れば十分なはずです。


またいつか新しいキーボードを手にした時の自分のための長いメモを以上で終えたいと思います。

東プレ REALFORCE 86U /静電容量無接点/変荷重/86キー/USB SE0500

東プレ REALFORCE 86U /静電容量無接点/変荷重/86キー/USB SE0500


GotW #3: 標準ライブラリを使う(もしくは一時オブジェクト再訪)(勝手訳)

第 3 回めの GotW の翻訳です。

例によって原文著者(Herb Sutter 氏)の許可は得ていませんし、私の英訳がヒドいクオリティである(用語の統一がとれていないとか、誤訳が含まれているとか)かもしれませんのでそこのところはご理解いただければと思います。


原文:http://herbsutter.com/2013/05/16/gotw-3-solution-using-the-standard-library-or-temporaries-revisited/



Effective reuse is an important part of good software engineering. To demonstrate how much better off you can be by using standard library algorithms instead of handcrafting your own, let’s reconsider the previous question to demonstrate how many of the problems could have been avoided by simply reusing what’s already available in the standard library.

効率的な再利用は、よいソフトウェア工学の重要な一部です。自作のものを使う代わりに標準ライブラリのアルゴリズムを使うことによってどれだけのメリットがもたらされるかを示すために、前回の質問をもう一度考えてみましょう。標準ライブラリにすでに存在しているものを単に再利用するだけで、そこで起こった問題がどれだけ回避できるかがわかるはずです。

Problem 問題

JG Question 見習いグルへの質問


1. What is the most widely used C++ library?

1. 最も広く使われている C++ のライブラリは何か?

Guru Question グルへの質問


2. How many of the pitfalls in GotW #2 could have been avoided in the first place, if only the programmer had replaced the explicit iterator-based for loop with:

2. GotW #2 の落とし穴のうち、明示的なイテレータベースの for ループを以下の方法で書き換えただけで、いくつの問題が回避されるか?


(a) a range-based for loop?
(b) a standard library algorithm call?

(a) 範囲ベースの for ループ
(b) 標準ライブラリアルゴリズムの呼び出し


Demonstrate. (Note: As with GotW #2, don’t change the semantics of the function, even though they could be improved.)

解答してください。(注意:GotW #2 と同様、関数のセマンティクスは変更しないでください。たとえ改善につながるとしても)


To recap, here is the mostly-fixed function:

以下は、前回の解答においてほぼ修正済みの関数です:

string find_addr( const list<employee>& emps, const string& name ) {
    for( auto i = begin(emps);  i != end(emps); ++i ) {
        if( i->name() == name ) {
            return i->addr;
        }
    }
    return "";
}

Solution 解答

1. What is the most widely used C++ library?

1. 最も広く使われている C++ のライブラリは何か?

The C++ standard library, with its implementations on every platform.

C++ 標準ライブラリ。すべてのプラットフォームにおいてその実装についてくるもの。


2. (a) How many of the pitfalls in GotW #2 could have been avoided with a range-based for loop?

2. GotW #2 の落とし穴のうち、明示的なイテレータベースの for ループを以下の方法で書き換えただけで、いくつの問題が回避されるか?

Astute readers of GotW #2 will have been champing at the bit to say: “Why aren’t you using a range-based for loop?” Indeed, why not? That would solve several of the temporaries, never mind be easier to write.

鋭い読者なら、GotW #2 の時から "範囲ベースの for loop を使ったらどうだい?" と言いたくてうずうずしていたことでしょう。確かにそうですね。そうすることでいくつかの一時オブジェクトの問題は解決しますし、むしろ書くのも簡単になるくらいです。

Compare the original unimproved explicit iterator loop:

比較してみましょう。
オリジナルの改善前の明示的イテレータループ:

    for( auto i = begin(emps); i != end(emps); i++ ) {
        if( *i == name ) {
            return i->addr;
        }
    }


with the range-based for loop (bonus points if you remembered to write the const auto&):

範囲ベースの for ループ(const auto& と書くことを覚えていたならボーナスポイントを差し上げます):

    for( const auto& e : emps ) {
        if( e == name ) {
            return e.addr;
        }
    }


The expressions e == name and return e.addr; are unchanged in terms of their possible or actual temporaries. But the questions in the naked loop code about whether or not the = causes a temporary (recall: it doesn’t), whether or not end() recalculation matters and should be hoisted (recall: probably not, but maybe), and whether or not i++ should be rewritten ++i (recall: it should) all simply don’t arise in the range-for code. Such is the power of clear code, and using a higher level of abstraction.

式 e == name と return e.addr; は一時オブジェクトができる可能性があることや実際にできてしまうという意味では変わっていません。しかし質問のループバージョンにあった、= が一時オブジェクトを生成するかどうか(実際にはしません)、end() の再計算が問題になるか、またループの外にくくり出されるべきか(おそらく問題にはなりませんが、なるかもしれません)、i++ は ++i と書きなおされるべきか(書きなおされるべきです)といったすべてのことが、範囲 for では単に問題になりません。これこそ、高度な抽象化を用いたクリアなコードのパワーです。


A key advantage is that using the range-based for loop has increased our level of abstraction, the information density in our code. Consider: What can you say about the following two pieces of code without reading what comes next?

範囲ベースの for ループを使うことの主なアドバンテージは、抽象化のレベルを上げ、コードの情報の精度を上げることです。次の2つのコード片について、次に何がくるかを読まずに何を言うことができるか考えてみてください。

    for( auto i = begin(emps); i != end(emps); i++ ) {   // A

    for( const auto& e : emps ) {                        // B

At first it might seem that lines A and B convey the same information, but they don’t. When you see A, all you know is that there’s a loop of some sort that uses an iterator over emps. Granted, we’re so used to A that our eye’s peripheral vision tends to “autocomplete” it in our heads into “a loop that visits the elements of emps in order” and our autocomplete is often correct—except when it isn’t: was that a ++, or a s+= 2 in a strided loop? is the index modified inside the body? Our peripheral vision might be wrong.

まず、行 A も B も同じ情報を含んでいるようだと思われますが、実際には違います。A を見てわかるのは、emps に対してイテレータを使って何らかのループをしているということです。確かに、私たちは A の形式に慣れていますし、私たちの目の周辺視野は頭のなかで "これは emps の要素を順に処理するループだ” と "オートコンプリート" しようとします。そしてそのオートコンプリートはたいてい正しいものです -- 間違っているとき以外は。もし ++ が +=2 だったら?そのインデックスはループ本体の中で変更されていない?私たちの周辺視野は間違えるかもしれません。


On the other hand, B conveys more information to the reader. When you see B, you know for certain without inspecting the body of the loop that it is a loop that visits the element of emps in order. What’s more, you’ve simplified the loop control because there’s no need for an iterator indirection. Both of these are raising the level of abstraction of our code, and that’s a good thing.

一方、B は読者に対してより多くの情報を与えます。B を見て、ループの本体を見なくても確実にわかるのは、これは emps の要素を順に処理するループであるということです。さらに、ループ制御がシンプルになります。イテレータによる間接参照が不要になるからです。これらのことはコードの抽象化のレベルを上げます。これは良いことです。


Note that, as discussed in GotW #2, the naked for loop didn’t naturally allow consolidating to a single return statement without resorting to making the code more complex by adding an additional variable and performing extra computation (a default construction followed by an assignment, instead of just a construction). That’s still true of the range-based for loop form, because it still has the two return statements in different scopes.

GotW #2 で議論したように、生の for ループを書くと必然的に return 文を一つだけにまとめることができません。一つにするには、コードを複雑にするような、変数の追加や余計な計算が必要になります(デフォルトコンストラクタによる構築と、代入が必要になります。ただ構築すれば良いだけではなくなります)。範囲ベースの for ループ形式でもそれは同じで、return 文をそれぞれ異なるスコープで2つ書かないといけないことには変わりありません。

2. (b) … with a standard library algorithm call?

2. (b) … 標準ライブラリアルゴリズムの呼び出しでは?


With no other changes, simply using the standard find algorithm could do everything the range-based for loop did to avoid needless temporaries (and questions about them):

他の変更なしで、単に標準の find アルゴリズムを使うことで、範囲ベースの for でできることは全てできて、かつ不要な一時オブジェクト(とそれにまつわる質問)を回避することができます。

// ベター (内部にフォーカス)
//
string find_addr( /*...*/ ) {
    const auto i = find( begin(emps), end(emps), name );   // はい、直してあげましたよ
    return i != end(emps) ? i->addr : "";
}


This naturally eliminates the same temporaries as the range-for version, and it further increases our level of abstraction. As with the range-based for loop, we can see at a glance and for certain that the loop will visit the elements of emps in order, but on top of that we also know we’re trying to find something and will get back an iterator to the first matching element if one exists. We do still have an iterator indirection, but only a single-use iterator object and no iterator arithmetic as in the original naked iterator for loop.

これは範囲ベースの for のバージョンと同じ一時オブジェクトを取り除きます。そして抽象化のレベルを更に引き上げます。範囲ベースの for ループのように、emps の要素に順に処理をするループであることがぱっと見で確定できます。その上、何かを見つけ(find)ようとしていて、もし見つかったら最初にマッチした要素へのイテレータが返されるということがわかります。イテレータによる間接参照はまだ残っていますが、イテレータオブジェクトは一度きりしか現れず、生のイテレータ for ループにあったようなイテレータの算術演算はありません。

Further, we have eliminated a loop nested scope entirely and flattened out the function to a single scope which can simplify this calling function in ways even the range-for couldn’t. To demonstrate still more just how fundamental this point is, note that what else the flattening out of the body buys us: Now, because the return statements are in the same scope (possible only because we eliminated the loop scope), we have the option of naturally combining them. You could still write if( i != end(emps) ) return i->addr; else return “”; here, on one or two or four lines, but there’s no need to. To be clear, the point here is not that reducing return statements should be a goal in itself—it shouldn’t be, and “single exit” thinking has always been flawed as we already saw in GotW #2. Rather, the point is that using an algorithm often simplifies our code more than an explicit loop, even a range-for loop, can do—not only directly by removing extra indirections and extra variables and a loop nested scope, but often also by permitting additional simplifications in nearby code.

さらに、ループのネストしたスコープをなくして関数を一つのスコープにフラットにして関数を単純に呼ぶだけにしました。これは範囲ベースの for でもできなかったことです。単にこの点が大変基本的なことというだけでないことを示すために、関数本体をフラットにすることが私たちにもたらしてくれるもう一つのことを強調しておきます:今、return 文が同じスコープにあるので(これはループのスコープを取り除いたことによってのみ可能なことです)、私たちはそれらを組み合わせることができます。if( i != end(emps) ) return i->addr; else return ""; と、1行もしくは2行、もしくは4行で書くこともできますが、そうする必要はありません。明確にしておきたいのですが、ここでのポイントは return 文の数を減らすことが自己目的化したゴールではないということです。またそうなるべきではありません。そして "一つの出口" という考えは、GotW #2 で見たように、常に間違っていました。ここでのポイントは、アルゴリズムを使うことは明示的なループを書くよりも私達のコードをよりシンプルにするものだ、ということです。余計な間接参照や余計な変数を取り除くことは範囲 for ループを使ってもできることではありますが、そのように直接的にシンプルにするだけではなく、周辺のコードのさらなるシンプル化を可能とします。

The above code might still cause a temporary when comparing an employee with a string, and we can eliminate even that temporary if we go one small step further and use find_if with a custom comparison that compares e.name() == name to avoid a possible conversion, assuming something like a suitable employee::name() is available as we did in GotW #2. Combining this with the other fixes to pass parameters by reference, we get:

上記のコードは employee を string と比較するときにまだ一時オブジェクトを生成します。その一時オブジェクトさえも取り除く事が可能です。もう一歩推し進めて、find_if をカスタム比較関数と合わせて使って e.name() == name で比較を行えば、発生しうる変換を回避できます。もちろんそれには GotW #2 でのように適切な employee::name() のようなものが使えるという前提です。これと引数を参照で渡すという修正を組み合わせると、こうなります:

// さらにベター (完成)
//
string find_addr( const list<employee>& emps, const string& name ) {
    const auto i = find_if( begin(emps), end(emps),
                      [&](const auto& e) { return e.name() == name; } );
    return i != end(emps) ? i->addr : "";
}

Summary まとめ


Prefer algorithm calls over explicit loops, when you have or can write a suitable algorithm that does what you want. They raise the level of abstraction and the clarity of our code. Scott Meyers’ advice in Effective STL is still true, and more applicable than even now that lambdas make algorithms much more usable than before:

あなたのしたい事をするようなアルゴリズムがすでにあるかあなたが書くことができるならば、明示的なループよりもアルゴリズム呼び出しを優先しましょう。それにより抽象化のレベルとコードの明快さが引き上げられます。Effective STL でのスコット・メイヤーズのアドバイスは今でも有効であり、以前よりもラムダがアルゴリズムをより使いでのあるものにした今となっては、そのアドバイスは一層当てはまります:

Guideline: Prefer algorithm calls to explicit loops. Algorithm calls are often clearer and reduce complexity. If no suitable algorithm exists, why not write it? You’ll use it again.

ガイドライン:明示的なループよりもアルゴリズム呼び出しを優先せよ。アルゴリズム呼び出しはより明快で、複雑さを低減させるものだ。適切なアルゴリズムが存在しなければ、それを書いてみよう。それを再利用することになるだろう。

Prefer reusing existing library code to handcrafting your own. The more widely used the library, the more likely it is to come well-designed, pre-debugged, and pre-optimized for many common requirements. And what library is more widely used than the standard library? In your C++ program, your standard library implementation is the most widely used library code you’re likely to use. This helps you both in the library’s design and its implementation: It’s full of code that’s intended to be used and reused, and to that end a lot of thought and care has gone into the design of its features, including its standard algorithms like find and sort. Implementers have also spent hours sweating over efficiency details, and usability details, and all sorts of other considerations so that you don’t have to—including performing optimizations you should almost never resort to in application-level code, such as using nonportable OS- and CPU-target specific optimizations.

自分で手作りするよりも既存のライブラリコードを再利用することを優先しましょう。ライブラリがより広く使われるようになると、そのライブラリは多くの一般的な要件に対してより良くデザインされ、事前にデバッグや最適化が済んでいるものになるでしょう。そして標準ライブラリよりも広く使われているライブラリはあるでしょうか?あなたの C++ プログラムの中で、あなたの標準ライブラリ実装が最も広く使われているライブラリコードで、あなたが使うべきものです。これはあなたをライブラリのデザインとその実装の両面で手助けします。標準ライブラリはすべて、利用され、再利用されることを意図して作られたコードです。find や sort のような標準的なアルゴリズムも含め、その機能のデザインにとてもたくさんの考えや配慮の集大成になっています。実装者は効率性の詳細や使いやすさの詳細、その他ありとあらゆる考慮しなければならないことに対して多大な時間をつぎ込み汗を流して来ました。あなたがそうしなくても良いように。あなたが決して使うことのなさそうな、移植性のない OS や CPU を対象にした固有の最適化といったような、最適化の実施もその中に含まれています。

So, always prefer to reuse code, especially algorithms and especially the standard library, and escape the trap of “I’ll-write-my-own-just-’cause-I-can.”

ですので、つねにコードの再利用を優先しましょう。アルゴリズムと特に標準ライブラリを。そして "自分で書けるから自分で書く" という罠を避けるようにしましょう。

Guideline: Reuse code—especially standard library code—instead of handcrafting your own. It’s faster, easier, and safer.

ガイドライン:自作するのではなく、コードを再利用せよ。特に標準ライブラリのコードを。それはより速いし、より簡単だし、より安全だ。

Acknowledgments 謝辞

Thanks in particular to the following for their feedback to improve this article: Olaf ven der Spek, Sam Kramer.

この記事をより良くするための以下の各位からのフィードバックに対し、特に感謝する:Olaf ven der Spek, Sam Kramer.

HHK / RealForce / Majestouch MINILA くらべ

私の職場では私は表題に掲げた3種のキーボードを使うことができるという幸運に恵まれています。

いずれも英語(US)配列のキーボードです。

せっかくなので、ここ数カ月間使ってみた感想等を書いてみます。
評価基準が偏ってるのであまり参考にならないかもしれませんが。

キーの配列については、以下の配列を標準と見なして、そこからの差分などについて言及します。

HHK


  • 雑感
      前職のときから使っていたので最も手に馴染んでいます。なので、この評価にはある程度バイアスがかかっていると思います。そこも含めて参考になさってください。
      無刻印モデルはさすがに手を出せなかったので薄墨モデルを使用しています。(たまに Print Screen キーを押したくなったりしたときに無刻印だと詰む)
      コンパクトさのためにキー配列がかなり特殊なので、慣れるのに時間を要するかもしれません。
      また、いったんこのキーボードに慣れてしまうと他のキーボードを触るのが苦痛になるかもしれません。


  • Good(個人的に 良い と感じる点)

    • ◇キー
      ちゃんと独自のスキャンコードを生成するため、Xmodmap とか AutoHotKey とかで使いやすい → 個人的に最大の評価ポイント
      例えばカーソルキーが無い代わりに ◇ + h, j, k, l で上下左右のキーコードを生成するように Xmodmap や AutoHotKey を設定することが容易になります。◇ キーをうまく使いこなせば、親指シフト的な、ホームポジションから手を動かさずにできることの幅がぐっと広がります。

    • 打鍵感
      個人的には一番好みです。軽すぎず重すぎないと感じます。

    • 打鍵音は静かなほうだと思います。


  • Bad

    • 標準の US 配列とかけ離れた位置にキーが配置されているものがあります。(~ など)

    • Windows キーが存在しません → Windows で使わなければ特に支障はありません

    • ほかにも存在しないキーや Fn との組み合わせでしか入力できないキーがたくさんあります。(とくに独立したカーソルキーが存在しないことが普通の方々には致命的かもしれません。emacs や vi のキーバインドで生きている人向けのキーボードでしょう)


  • キー配置の特徴(標準配列との違い)

    • デフォルトでは Backspace キーは存在せず、Delete キーになっています。ディップスイッチにより Delete キーを Backspace キーに切り替え可能です。このあとはディップスイッチによって Delete キーを Backspace キーに切り替えた前提で書きます。

    • Backspace キーは Enter キーの直上にあります。標準では \(バックスラッシュ) |(パイプ) キーがある位置です。\| キーはさらにその上(一番上の段)にあります。標準では Backspace キーになっているキーが左右2つに分割されて、その左側のキーが \| キーに、右側のキーが `(バッククオート) ~(チルダ)キーになっています。

    • Esc キーは 1 の左、Tab キーの上にあります。標準では `~ キーがある位置です。

    • Caps Lock キーは Fn キー + Tab です。

    • 左 Control キーは標準 Caps Lock キーの位置にあります。標準では左 Control キーがある位置(キーボードの一番左下)には、物理的にキーが存在しません。

    • 標準では Super キーが存在する位置に、Alt キーがあります。(左右とも)

    • 標準では Alt キーが存在する位置に、◇ キーがあります。(左右とも)

    • Meta キーおよび右 Control キーは存在しません。

    • 上下左右のカーソルキーは存在しません。Fn キーとの組み合わせで実現します。

    • F1〜F12 キーは存在しません。Fn キーとの組み合わせで実現します。

    • Ins、Home、Page Up などのキーも存在しません。Fn キーとの組み合わせで実現します。


  • その他

    • USB ハブのように使えるポートを 2 ポート持っています

    • PC 本体と接続する USB ケーブルは着脱可能です。キーボード側のコネクタは USB mini B です。




Majestouch Minila

Majestouch MINILA US67キー 茶軸 FFKB67M/EB

Majestouch MINILA US67キー 茶軸 FFKB67M/EB


  • Good

    • ディップスイッチで交換できるキーのために、交換用キートップがついてきます。
      例)CapsLock キーを Ctrl に変更する人のために、CapsLock と同じ大きさの Ctrl キーのキートップが付属している。
      ディップスイッチでキー配置を変えたとしても大丈夫!

    • キートップ交換用の治具(キートップを引き抜くための道具)がついてくる
      地味に便利


  • Bad

    • 打鍵感が軽めです。HHKRealforce を使ったあとだと、手応え不足を感じます。(茶軸だからかもしれません)

    • 打鍵音が大きめです。軽いカチャカチャという音がします。(茶軸だからかもしれません。)

    • 親指 Fn キーがスキャンコードを発生しないので Xmodmap とか AutoHotKey で使えません。FILCO お仕着せのキーバインドのためにしか使えません。
      非常にもったいない。このキーボードの最大のマイナスポイントです。


  • キー配置の特徴

    • Esc キーの位置が特殊です。標準配列では `~ キーになっている場所に Esc キーがあります。Fn + Esc で `~ キーになります。また、ディップスイッチにより ESC キーを恒常的に`~ キーに変えることが可能です。その際 Esc キーは Fn + ` にります。

    • `~ は Fn との組み合わせで実現するだけでなく、普通のキーとしても配置されています。最上段の右から 2 番目にあります。標準配列では Backspace になっている横長のキーが左右に分割されて、その左側のキーが `~ キーになっています。(右側は Backspace です)

    • Enter キーの上は標準配列どおり \| キーになっています。

    • Backspace と \| キーは、ディップスイッチにより入れ替えが可能です。

    • 私は AutoHotKey で `~ キーを \| キーと入れ替えて HHK っぽくして使っています。

    • 左 Super キーは Windows キー、右 Super キーは App キーになっています。Meta キーに相当するキーはないようです。

    • キーボード右下に無理やりカーソルキーを押し込んだような配置のため、カーソルキーはあまり押しやすくはないです。右 Shift キーと Delete キーも申し訳程度についてますが、キーを見ないで押すことが(いまだに)できません。


  • その他

    • USB ハブのように使えるポートを 1 ポート持っています。

    • PC 本体と接続する USB ケーブルは着脱可能です。キーボード側のコネクタは USB mini B です。




RealForce

東プレ REALFORCE 86U /静電容量無接点/変荷重/86キー/USB SE0500

東プレ REALFORCE 86U /静電容量無接点/変荷重/86キー/USB SE0500


  • Good

    • 標準配列に忠実なキー配置です。標準との違いは、最初から左 Control キーと Caps Lock キーが入れ替わっていることと、Meta キーに相当するキーが存在しないことくらいでしょうか。3 つの中では最も素直で万人に受け入れられやすいキー配置ではないでしょうか。

    • 打鍵音は静かなほうです。HHK との違いはほとんど感じません。


  • Bad

    • 打鍵感が重めです。ずっと打っていると疲れます。私の力加減がよくないのかもしれません。(私はしっかりと最後まで押しこみたいタイプです)

    • 他の 2 製品と比べて、Esc キーが遠く感じます。vi 使いにはツラいところです。

    • USB ケーブルがキーボード本体に直結されているので、必要な長さにあわせてケーブルを取り替えたりすることができません。長くしたい分には延長することも可能かもしれませんが、短くすることができません。キーボードのケーブルは意外と机の上で邪魔になるものです。

    • それほど重大な問題ではありませんが、USB ハブとしての機能はありません

    • 設置面積は 3 製品中最大です。F1〜F12 キーや Ins/Home/Page Up などのキー、カーソルキーが余裕を持って配置されているためだと思います。逆にその余裕のおかげでそれらのキーもブラインドタッチできますので、メリットと感じる人もいるかもしれません。

  • キー配置の特徴

    • Good のところで書いた2点以外にキー配置上の特徴らしい特徴はありません。逆にそのことが特徴なのかもしれません。



まとめ

やっぱり個人的には HHK がベストかな、という結論に落ち着きました。
単に、より使い慣れているというだけのような気もしますが、キー配置のカスタマイズ時に◇キーが使えるのが大きいですね。

git svn でローカルでは commit したけどまだ dcommit してないコミットがあるかどうかをコマンドラインで調べる方法

人間が目で見て把握するには gitk などの GUI ツールでもあれば十分なのですが、機械にそれを調べさせるにはコマンドで実行したいところです。

調べたところ、以下のワンライナーで十分なようです。

$ git log remotes/git-svn.. --oneline

GotW #2: Temporary Objects 一時オブジェクト(勝手訳)

第2回めの GotW の翻訳です。

例によって原文著者(Herb Sutter 氏)の許可は得ていませんし、私の英訳がヒドいクオリティである(用語の統一がとれていないとか、誤訳が含まれているとか)かもしれませんのでそこのところはご理解いただければと思います。


原文:http://herbsutter.com/2013/05/13/gotw-2-solution-temporary-objects/


Unnecessary and/or temporary objects are frequent culprits that can throw all your hard work—and your program’s performance—right out the window. How can you spot them and avoid them?

必要がなかったり一時的にしか使われない(もしくはその両方であるような)オブジェクトは、あなたの大変な努力を - そしてあなたのプログラムのパフォーマンスを - 台無しにすることがあります。

Problem 問題

JG Question 見習いグルへの質問


1. What is a temporary object?

1. 一時オブジェクトとは何か?

Guru Question グルへの質問


2. You are doing a code review. A programmer has written the following function, which uses unnecessary temporary or extra objects in at least three places. How many can you identify, and how should the programmer fix them?

2. あなたはコードレビューを行なっている。あるプログラマが以下のような関数を書いた。その中では不必要な一時オブジェクトや余分なオブジェクトが少なくとも3箇所で使われている。あなたはいくつ見つけられるか?そしてそのプログラマはどのようにそれを直すべきか?

string find_addr( list<employee> emps, string name ) {
    for( auto i = begin(emps); i != end(emps); i++ ) {
        if( *i == name ) {
            return i->addr;
        }
    }
    return "";
}


Do not change the operational semantics of this function, even though they could be improved.

この関数の動作上のセマンティクスを変更してはならない。たとえそれが改善につながるとしても。

Solution 解

1. What is a temporary object?

1. 一時オブジェクトとは何か?

Informally, a temporary object is an unnamed object that you can’t take the address of. A temporary is often created as an intermediate value during the evaluation of an expression, such as an object created by returning a value from a function, performing an implicit conversion, or throwing an exception. We usually call a temporary object an “rvalue,” so named because it can appear on the “r”ight hand side of an assignment. Here are some simple examples:

正式な言い方ではありませんが、一時オブジェクトとはそのアドレスを取得することができない無名オブジェクトです。一時オブジェクトはしばしば、関数からのリターン、暗黙の変換の実行もしくは例外のスローによって生成されるオブジェクトのような、式の評価の間の中間的な値として生成されます。私たちは通常、一時オブジェクトのことを rvalue と呼びます。代入文の右辺("r"ight hand side)に現れるものだからです。いくつかのシンプルな例をお見せします:

widget f();            // f は 一時的な widget オブジェクトを返す

auto a = 0, b = 1;
auto c = a + b;        // "a+b" は一時的な int オブジェクトを生成する

In contrast, in the same code we have objects like a and c that do each have a name and a memory address. Such an object is usually called an “lvalue,” because it can appear on the “l”eft hand side of an assignment.

対照的に、同じコードの中にある a や c のようなオブジェクトは名前とメモリアドレスを持ちます。そのようなオブジェクトは通常 lvalue と呼ばれます。代入文の左辺("l"eft hand side)に現れるものだからです。


That’s a simplification of the truth, but it’s generally all you need to know. More precisely, C++ now has five categories of values, but distinguishing them is primarily useful for writing down the language specification, and you can mostly ignore them and just think about “rvalues” for temporary objects without names and whose addresses can’t be taken, and “lvalues” for non-temporary objects that have names and whose addresses can be taken.

これは真実を簡略化していますが、普通の人が知っておく分にはこれで十分です。より正確には、C++ には今や5つの値のカテゴリがありますが、それらを区別するのは言語仕様を書くには便利ですが、普通の人は気にする必要がありません。とにかく "rvalue” は名前を持たない一時的なオブジェクトでそのアドレスを取得すことができない、"lvalue" は一時的ではないオブジェクトで名前を持ちアドレスを取得することができると考えてよいでしょう。


2. How many unnecessary temporary objects can you identify, and how should the programmer fix them?

2. あなたはいくつの不要な一時オブジェクトを見つけられるか?そしてそのプログラマはどのようにそれを直すべきか?

Believe it or not, this short function harbors three obvious cases of unnecessary temporaries or extra copies of objects, two subtler ones, and three red herrings.

信じるかどうかは別として、この短い関数には不要な一時オブジェクトや余分なオブジェクトのコピーが明らかなものが3つ、微妙なものが2つ、そして3つの囮が隠れています。


The parameters are passed by value.

パラメータが値で渡されている。

The most obvious extra copies are buried in the function signature itself:

最も明らかな余分なコピーは関数シグネチャ自体に含まれています:

  string find_addr( list<employee> emps, string name )

The parameters should be passed by const&—that is, const list& and const string&, respectively—instead of by value. Pass-by-value forces the compiler to make complete copy of both objects, which can be expensive and, here, is completely unnecessary.

パラメータは値ではなく const& で渡されるべきです。つまり、それぞれ const list& と const string& となります。値渡しはコンパイラに両方のオブジェクトの完全なコピーを作らせますが、それは高価なものになりえますし、完全に不要です。

Guideline: Prefer passing a read-only parameter by const& if you are only going to read from it (not make a copy of it).

ガイドライン:読み取り専用のパラメータは const& で渡すようにする。(コピーを作らない)


Pedantic note: Yes, with pass-by-value, if the caller passed a temporary list or string argument then it could be moved from rather than copied. But I’m deliberately saying “forces the compiler to make a complete copy” here because no caller is realistically going to be passing a temporary list to find_addr, except by mistake.

厳密には、値渡しであっても呼び出し元が引数として一時オブジェクトを渡したら、それはコピーされるのではなくてムーブされるかもしれません。しかし私は意図的に "コンパイラに完全なコピーを作らせる” と言いました。間違いを除いて呼び出し元が list の一時オブジェクトを find_addr に渡すことは現実的にはないからです。

Non-issue: Initializing with “=”.

問題なし:"=" による初期化

Next we come to the first red herring, in the for loop’s initialization:

次に最初の囮に差し掛かります。for ループの初期化部において:

    for( auto i = begin(emps); /*...*/ )

You might be tempted to say that this code should prefer to be spelled auto i(begin(emps)) rather than auto i = begin(emps), on the grounds that the = syntax incurs an extra temporary object, even if it might be optimized away. After all, as we saw in GotW #1, usually that extra = means the two-step “convert to a temporary then copy/move” of copy-initialization—but recall that doesn’t apply when using auto like this. Why?

あなたはもしかしたら、"このコードは auto i = begin(emps) ではなくて auto i(begin(emps)) と書くべきだよ、= シンタックスはたとえ最適化可能だとはいえ余分な一時オブジェクトを作るよ"、と言いたくなったのではないでしょうか?どのみち、GotW #1 で見たように、通常はその余分な = は2ステップの "一時オブジェクトに変換してからコピーかムーブ" のコピー初期化を意味します。しかし、それはここでのように auto を使っている時には当てはまらなかったことを思い起こしてください。なぜでしょうか?

Remember that auto always deduces the exact type of the initializer expression, minus top-level const and & which don’t matter for conversions, and so… presto! there cannot be any need for a conversion and we directly construct i.

auto は常に初期化式の正確な型を推測します。そしてトップレベルの const と & は変換には関係ありません。そして、、、そう!変換が一切不要なので i を直接構築することができます。

So there is no difference between auto i(begin(emps)) and auto i = begin(emps). Which syntax you choose is up to you, but it depends only on taste, not on temporaries or any other performance or semantic difference.

なので auto i(begin(emps)) と auto i = begin(emps) の間には何も違いがありません。どちらのシンタックスを選ぶかはあなた次第ですが、それは単に好みの問題であって、一時オブジェクトなどのパフォーマンスやセマンティックの違いはありません。

Guideline: Prefer declaring variables using auto. Among other reasons to do so, it naturally guarantees zero extra temporaries due to implicit conversions.

ガイドライン:auto を使って変数を宣言するようにする。そうするべき理由はいくつかあるが、必然的に暗黙の変換による余分な一時オブジェクトが生成されないことが保証される。

The end of the range is recalculated on each loop iteration.

範囲の終端はループの各繰り返しごとに再計算される。

Another potential avoidable temporary occurs in the for loop’s termination condition:

もうひとつの回避可能な一時オブジェクトは for ループの終了条件に見られます:

  for( /*...*/ ; i != end(emps); /*...*/ )

For most containers, including list, calling end() returns a temporary object that must be constructed and destroyed, even though the value will not change.

list を含めほとんどのコンテナにおいて、end() の呼び出しは一時オブジェクトを返します。一時オブジェクトは構築され、破棄されます。たとえその値が変化しないとしてもです。

Normally when a value will not change, instead of recomputing it (and reconstructing and redestroying it) on every loop iteration, we would want to compute the value only once, store it in a local object, and reuse it.

普通、値が変化しないときは、それをループの繰り返しごとに再計算する代わりに(そして再構築と再破棄する代わりに)、その値を一度だけ計算してそれをローカルオブジェクトとして保存しておき、再利用したいと思うはずです。

Guideline: Prefer precomputing values that won’t change, instead of recreating objects unnecessarily.

ガイドライン:値が変化しない場合は、不必要にオブジェクトを再生成するのではなく、前もって計算した値を使うようにする。

However, a caution is in order: In practice, for simple inline functions like list::end() in particular used in a loop, compilers routinely notice their values won’t change and hoist them out of the loop for you without you having to do it yourself. So I actually don’t recommend any change to hoist the end calculation here, because that would make the code slightly more complex and the definition of premature optimization is making the code more complex in the name of efficiency without data that it’s actually needed. Clarity comes first:

しかしながら、注意があります:実際には、list::end() のようなシンプルなインライン関数に対しては、特にループのなかで使われる場合、コンパイラはその値が変化しないことに普通は気づいてそれをループの外に取り出します。あなたが自分でそれをやる必要はありません。なので私は end の計算をループの外に取り出すようにとはおすすめしません。コードが複雑になりますし、早すぎる最適化は効率性の名のもとに実際には必要なデータなしに効率性の名のもとにコードをより複雑にしてしまうからです。明快さが第一です:

Definition: Premature optimization is when you make code more complex in the name of efficiency without data that it’s actually needed.

定義:早すぎる最適化 とは、必要なデータなしに効率性の名のもとにコードを複雑にしてしまうこと

Guideline: Write for clarity and correctness first. Don’t optimize prematurely, before you have profiler data proving the optimization is needed, especially in the case of calls to simple inline calls to short functions that compilers normally can handle for you.

ガイドライン:まず、明快さと正しさのために書く。最適化が必要であることを示すプロファイラのデータが得られるまでは、早すぎる最適化をしない。特にシンプルなインライン関数は通常コンパイラがそれを適切に扱ってくれる。

The iterator increment uses postincrement.

イテレータのインクリメントに後置インクリメントを使っている。

Next, consider the way we increment i in the for loop:

次は、for ループにおいて i をインクリメントする方法について考えてみよう:

  for( /*...*/ ; i++ )


This temporary is more subtle, but it’s easy to understand once you remember how preincrement and postincrement differ. Postincrement is usually less efficient than preincrement because it has to remember and return its original value.

この一時オブジェクトはより気づきにくいが、前置インクリメントと後置インクリメントがどう違うかが一度わかってしまえば理解するのはたやすいことです。後置インクリメントは通常、前置インクリメントよりも効率的ではありません。オリジナルの値を覚えておいて返さなければならないからです。

Postincrement for a class T should normally be implemented using the canonical form as follows:

クラス T に対する後置インクリメントは普通、以下の様な正規化された形式を使って実装されます。

T T::operator++(int)() {
    auto old = *this; // remember our original value
    ++*this;          // always implement postincr in terms of preincr
    return old;       // return our original value
}


Now it’s easy to see why postincrement is less efficient than preincrement: Postincrement has to do all the same work as preincrement, but in addition it also has to construct and return another object containing the original value.

もう後置インクリメントが前置インクリメントよりも効率的でない理由がお分かりでしょう。後置インクリメントは前置インクリメントと全く同じ仕事をする必要がありますが、それに加えてオリジナルの値を保持するもう一つのオブジェクトを作って返す必要もあります。

Guideline: For consistency, always implement postincrement in terms of preincrement, otherwise your users will get surprising (and often unpleasant) results.

ガイドライン:一貫性のため、常に後置インクリメントは前置インクリメントを使って実装する。そうしなければ驚くような(そしてうれしくない)結果をユーザにもたらすことになります。

In the problem’s code, the original value is never used, and so there’s no reason to use postincrement. Preincrement should be used instead. Although the difference is unlikely to matter for a built-in type or a simple iterator type, where the compiler can often optimize away the extra unneeded work for you, it’s still a good habit not to ask for more than you need.

問題のコードでは、オリジナルの値は使われていませんので、後置インクリメントを使う理由はありません。代わりに前置インクリメントが使われるべきです。組込みの型であるかシンプルなイテレータ型であるかといった違いにはほとんど関係なく、コンパイラは最適化により余計なものを取り除いてくれますが、それでも必要以上のことはやらないほうが良いでしょう。

Guideline: Prefer preincrement. Only use postincrement if you’re going to use the original value.

ガイドライン:前置インクリメントを優先的に使用せよ。オリジナルの値を使いたいときだけ後置インクリメントを使用せよ。

“But wait, you’re being inconsistent!” I can just hear someone saying. “That’s premature optimization. You said that compilers can hoist the end() call out of the loop, and it’s just as easy for a compiler to optimize away this postincrement temporary.”

"でも待って、君が言ってることは一貫性がないよ!" 誰かがそう言ったのが聞こえました。"これは早すぎる最適化ってやつだよ。コンパイラは end() をループの外に出してくれるって言ったし、この後置インクリメントの一時オブジェクトを最適化して取り除くのもコンパイラにとってはたやすいことだって言ったじゃない。"

That’s true, but it doesn’t imply premature optimization. Preferring ++i does not mean writing more complex code in the name of performance before you can prove it’s needed—++i is not more complex than i++, so it’s not as if you need performance data to justify using it! Rather, preferring ++i is avoiding premature pessimization, which means avoiding writing equivalently complex code that needlessly asks for extra work that it’s just going to ignore anyway.

それはたしかにそうですが、これは早すぎる最適化ではありません。++i を優先的に使うというのは、パフォーマンスの名のもとにそれが本当に必要であると証明される前に複雑なコードを書くこととは違います。++i は i++ よりも複雑だということはありません。これを使うのを正当化するためにパフォーマンスデータは要りません。逆に、++i を使うことは "早すぎる最悪化(pessimization)" を避けることになります。同程度の複雑さのコードを書くことで、ただ無視されるだけの余計なものを不要に作らせることを回避するからです。

Definition: Premature pessimization is when you write code that is slower than it needs to be, usually by asking for unnecessary extra work, when equivalently complex code would be faster and should just naturally flow out of your fingers.

定義:早すぎる最悪化とは、不要な余計なことをさせるなど、必要以上に遅いコードを書くこと。また同程度の複雑さのコードのほうが速く、それが自然に書くことができること。


The comparison might use an implicit conversion.

比較は暗黙の変換を伴うかもしれない。

Next, we come to this:

次は、ここです:

    if( *i == name )


The employee class isn’t shown in the problem, but we can deduce a few things about it. For this code to work, employee likely must either have a conversion to string or a conversion constructor taking a string. Both cases create a temporary object, invoking either operator== for strings or operator== for employees. (Only if there does happen to be an operator== that takes one of each, or employee has a conversion to a reference, that is, string&, is a temporary not needed.)

employee クラスは問題の中では提示されていませんが、いくつか推測することができます。このコードを動かすためには、employee は string への変換もしくは string を受け取る変換コンストラクタのいずれかを持っていなければならないでしょう。どちらのケースでも一時オブジェクトが作られ、string に対する operator== もしくは employee に対する operator== が起動されます。(operator== が参照(string&)を受け取るか、employee が参照(string&)への変換を持っている場合に限り、一時オブジェクトは必要ありません)

Guideline: Watch out for hidden temporaries created by implicit conversions. One good way to avoid this is to make constructors and conversion operators explicit by default unless implicit conversions are really desirable.

ガイドライン:暗黙の変換によって作られる、隠れた一時オブジェクトに注意しなさい。これを避けるための一つの良い方法は、コンストラクタと変換演算子を explicit にすることです。(暗黙の変換が本当に必要な場合を除く)

Probably a non-issue: return “”.

おそらく問題ではない:return ""

    return "";


Here we unavoidably create a temporary (unless we change the return type, but we shouldn’t; see below), but the question is: Is there a better way?

この場合、一時オブジェクトを作ることは不可避です(ただし戻り値の型を変更することが出来る場合を除く。しかしそうするべきではない。後述)。問題は:もっといい方法はあるか?です。

As written, return “”; calls the string constructor that takes a const char*, and if the string implementation you’re using either (a) is smart enough to check for the case where it’s being passed an empty string, or (b) uses the small string optimization (SSO) that stores strings up to a certain size directly within the string object instead of on the heap, no heap allocation will happen.

書かれてあるとおり、return ""; は string の const char* を引数にとるコンストラクタを呼びます。そしてあなたの使っている string の実装が以下のいずれかの場合、ヒープの確保は起こりません。(a) 空文字列が渡されたことをチェックするような、十分賢い実装になっている。(b) small string optimization (SSO) を使って、ある特定のサイズまでの文字列は直接 string オブジェクトの中に格納し、ヒープを使わないようになっている。

Indeed, every string implementation I checked is smart enough not to perform an allocation here, which is maximally efficient for string, and so in practice there’s nothing to optimize. But what alternatives do we have? Let’s consider two.

たしかに、私のチェックしたすべての string の実装は十分にスマートで、ここではメモリ確保は発生しないようになっていました。これは string としては最大限に効率的です。そして実際に最適化するべきものは何もありません。しかし、他の代替案はないでしょうか?2つ考えてみましょう。


First, you might consider re-spelling this as return “”s; which is new in C++14. That essentially relies on the same implementation smarts to check for empty strings or to use SSO, just in a different function—the literal operator”".

まず、return ""s; と書き換えてみることを考えることができます。これは C++14 で新しく導入されたものです。これは空文字列をチェックするスマートな実装やSSOを使うことと同じものに本質的に頼っています。違うのはリテラル演算子 operator"" です。

Second, you might consider re-spelling this as return { };. On implementations that are both non-smart and non-SSO, this might have a slight advantage over the others because it invokes the default constructor, and so even the most naïve implementation is likely not to do an allocation since clearly no value is needed.

2つ目は、return {}; と書き換えることを考えることができます。スマートでもなく SSO でもない実装においても、これは他の方法に比べてちょっとしたアドバンテージを持つかもしれません。これはデフォルトコンストラクタを起動し、明らかに値が不要なので、最もナイーブな実装であったとしてもメモリ確保をしないでしょう。

In summary, there’s no difference in practice among returning “”, “”s, or { }; use whichever you prefer for stylistic reasons. If your string implementation is either smart or uses SSO, which covers all implementations I know of, there’s exactly zero allocation difference.

まとめると、""、""s もしくは {} を返すことの間には実際的な違いはありません。スタイル上の理由で好きなものをどれでも使えば良いと思います。あなたの使っている string の実装がスマートであるか SSO を使っている場合、そしてそれは私の知る限りすべての実装をカバーしていますが、メモリ確保に関しては全く違いがありません。


Note: SSO is a wonderful optimization for avoiding allocation overhead and contention, and every modern string ought to use it. If your string implementation doesn’t use SSO (as of this writing, I’m looking at you, libstdc++), write to your standard library implementer—it really should.

注:SSO はメモリ確保のオーバーヘッドや競合を回避するための素晴らしい最適化であり、すべての近代的な string が持つべきものです。もしあなたの string の実装が SSO を使っていないなら(これを書いている時点では、libstdc++、君のことを言っているんだよ)、あなたは標準ライブラリの実装者に「マジで実装するべきだ」といってあげてください。


Non-issue: Multiple returns.

問題ではない:複数の return

    return i->addr;
    return "";


This was a second subtle red herring, designed to lure in errant disciples of the “single-entry/single-exit” (SE/SE) persuasion.

これは2つ目の微妙な罠です。”一つの入口/一つの出口" (single-entry/single-exit: SE/SE) という信条の常軌を逸した信奉者を引っ掛けるための釣り餌として用意しました。

I In the past, I’ve heard some people argue that it’s better to declare a local string object to hold the return value and have a single return statement that returns that string, such as writing string ret; … ret = i->addr; break; … return ret;. The idea, they say, is that this will assist the optimizer perform the ‘named return value optimization.’

過去に、ある人々が以下の様な議論をしているのを聞いたことがあります。すなわち、戻り値を保持するローカルの string オブジェクトを宣言して、その string を return する return 文を一つだけ持つのが良い。たとえば string ret; ... ret = i->addr; break; ... return ret; というように書く。このアイディアは、彼らが言うには、オプティマイザが 'named return value optimization(名前付き戻り値最適化)' を行うのを助けるというのです。

The truth is that whether single-return will improve or degrade performance can depend greatly on your actual code and compiler. In this case, the problem is that creating a single local string object and then assigning it would mean calling string’s default constructor and then possibly its assignment operator, instead of just a single constructor as in our original code. “But,” you ask, “how expensive could a plain old string default constructor be?” Well, here’s how the “two-return” version performed on one popular compiler last time I tried it:

真実は、ひとつの return がパフォーマンスを改善するか改悪するかというのは実際のコードとコンパイラに大きく依存しているということです。このケースでは、一つのローカル string オブジェクトを生成してそれに後から値を代入するというのは、string のデフォルトコンストラクタを呼び出し、かつ代入演算子も呼び出すという事になるでしょう。一方、オリジナルのコードではコンストラクタが一度だけ呼び出されます。"でも"、とあなたは言います。"string の単純なデフォルトコンストラクタがどれくらい高価だっていうんだい?" ええと、私が最近試した、あるポピュラーなコンパイラにおいて "2つの return" バージョンのパフォーマンスはこうでした:

  • with optimizations disabled: two-return 5% faster than a “return value” string object
  • with aggressive optimizations: two-return 40% faster than a “return value” string object
  • 最適化オフ:2つのreturn は "戻り値" string オブジェクトよりも 5% 速い
  • 最適化 MAX:2つのreturn は "戻り値" string オブジェクトよりも 40% 速い


Note what this means: Not only did the single-return version generate slower code on this particular compiler on this particular day, but the slowdown was greater with optimizations turned on. In other words, a single-return version didn’t assist optimization, but actively interfered with it by making the code more complex.

これが意味するところに注意:1つの return バージョンはこの特定の日にこの特定のコンパイラにおいて遅いコードを生成しただけではなく、最適化を ON にしたときにスローダウンが大きくなりました。言い換えると、1つの return バージョンは最適化を支援しませんでした。むしろコードを複雑にすることによって積極的に最適化の邪魔をしました。

In general, note that SE/SE is an obsolete idea and has always been wrong. “Single entry,” or the idea that functions should always be entered in one place (at their start) and not with goto jumps from the caller’s code directly to random places inside the function body, was and is an immensely valuable advance in computer science. It’s what made libraries possible, because it meant you could package up a function and reuse it and the function would always know its starting state, where it begins, regardless of the calling code. “Single exit,” on the other hand, got unfairly popular on the basis of optimization (‘if there’s a single return the compiler can perform return value optimization better’—see counterexample above) and symmetry (‘if single entry is good, single exit must be good too’) but that is wrong because the reasons don’t hold in reverse—allowing a caller to jump in is bad because it’s not under the function’s control, but allowing the function itself to return early when it knows it’s done is perfectly fine and fully under the function’s control. To put the final nail in the coffin, note that “single exit” has always been a fiction in any language that has exceptions, because you can get an early exceptional return from any point where you call something that could throw an exception.

一般的に、SE/SE は時代遅れのアイディアで、常に間違っていました。”一つの入口" 、もしくは関数には常にひとつの場所(開始地点)から入ってくるべきであって呼び出し元のコードから直接 goto ジャンプで関数本体の内側のデタラメな場所から入ってくるべきではないという考えは、コンピュータサイエンスにおける偉大で価値のある進歩です。関数は呼び出し元のコードに関係なく、常にその開始状態を知っているので、そのおかげで関数をパッケージして再利用することができてライブラリを作ることができます。一方、"一つの出口" は不当にポピュラーになってしまいました。最適化('return がひとつだけならコンパイラは戻り値の最適化をよりうまくやれる'というもの - 上の反例を参照)や対称性('一つの入口 が良いのなら、一つの出口もまた良いのだろう’)にもとづいていますが、それは間違いです。それらの理由は逆に成り立たないからです。呼び出し元からジャンプして入ってくることを許すのは悪いことです。その関数のコントロールの及ばないことだからです。しかしその関数から早く return することは、それがいつ行われるかがわかっていれば全く問題ありません。その関数のコントロール下にあることだからです。とどめに、"一つの出口" は例外機構を持ついかなる言語においても、常にフィクションに過ぎません。例外を投げる可能性のあるものを呼び出すところではどこでも例外によって関数から抜けだしてしまうことができるからです。

Non-issue: Return by value.

問題なし:値による return

Which brings us to the third red herring:

3番目の罠です:

string find_addr( /*...*/ )


Because C++ naturally enables move semantics for returned values like this string object, there’s usually little to be gained by trying to avoid the temporary when you return by value. For example, if the caller writes auto address = find_addr( mylist, “Marvin the Robot” );, there will be at most a cheap move (not a deep copy) of the returned temporary into address, and compilers are allowed to optimize away even that cheap move and construct the result into address directly.

C++ はこの string オブジェクトのような戻り値に対して当然のようにムーブセマンティクスを有効にしますので、値を返すときに一時オブジェクトを避けようとしても通常は得るものはほとんどないでしょう。たとえば、呼び出し元が auto address = find_addr(mylist, "Marvin the Robot"); と書いたとすれば、戻り値の一時オブジェクトは address に対してディープコピーではなくせいぜい安価なムーブになるでしょうし、コンパイラはその安価なムーブを最適化して取り除いて address に直接結果を構築することもできます。

But what if you did feel tempted to try to avoid a temporary in all return cases by returning a string& instead of string? Here’s one way you might try doing it that avoids the pitfall of returning a dangling reference to a local or temporary object:

もしあなたに、すべての return で string を使う代わりに string& を返すことで一時オブジェクトを回避しようとする魔が差したとしたらどうでしょう?ローカルオブジェクトや一時オブジェクトへの宙ぶらりんの(dangling)参照を返してしまう落とし穴を回避しながらあなたが試すかもしれない一つの方法はこうなるでしょう:

const string& find_addr( /* ... */ ) {
    for( /* ... */ ) {
        if( /* found */ ) {
            return i->addr;
        }
    }
    static const string empty;
    return empty;
}


To demonstrate why this is brittle, here’s an extra question:

これが脆弱であることを示すために、もう一つ問題です:

For the above function, write the documentation for how long the returned reference is valid.

上記の関数において、返された参照がどのくらいの期間有効であるかを説明するドキュメントを書きなさい。

Go ahead, we’ll wait.

さあどうぞ。待ってます。


Done? Okay, let’s consider: If the object is found, we are returning a reference to a string inside an employee object inside the list, and so the reference itself is only valid for the lifetime of said employee object inside the list. So we might try something like this (assuming an empty address is not valid for any employee):

終わりましたか?オーケー、それでは考えてみましょう:もし object が見つかったら、list の中の employee オブジェクトの中の string への参照を返すことになります。したがってその参照自身は、その list の中の employee オブジェクトの有効期間の間だけ有効です。したがってあなたはこのようなことを言ってみるかもしれません(空の住所はどんな employee に対しても有効でないと仮定します):

“If the returned string is nonempty, then the reference is valid until the next time you modify the employee object for which this is the address, including if you remove that employee from the list.”

"返される文字列が空でない場合、その参照は、その address を持っている employee オブジェクトが次に変更される時まで有効です。変更にはその employee オブジェクトが list から削除されることも含みます。”

Those are very brittle semantics, not least because the first (but far from only) problem that immediately arises is that the caller has no idea which employee that is—not only doesn’t he have a pointer or reference to the right employee object, but he may not even be able to easily figure out which one it is if two employees could have the same address. Second, calling code can be notoriously forgetful and careless about the lifetimes of the returned reference, as in the following code which compiles just fine:

とても脆弱なセマンティクスです。特に、数ある問題のうちすぐに起こる最初の問題は、呼び出し元はその employee オブジェクトが何かわかりません。正しい employee オブジェクトへのポインタも参照もわからないだけでなく、2つの employee が同じ address を持っていたらそのどちらなのかを簡単に判別することもできません。2つ目の問題は、呼び出し元のコードというのは、返されたリファレンスの有効期間について、すぐに忘れてしまって気にもしないものだということです。コンパイルは問題なく通る以下のコードのように:

auto& a = find_addr( emps, "John Doe" );  // イェイ、一時オブジェクトを回避したぜ!
emps.clear();
cout << a;                                // おっと

When the calling code does something like this and uses a reference beyond its lifetime, the bug will typically be intermittent and very difficult to diagnose. Indeed, one of the most common mistakes programmers make with the standard library is to use iterators after they are no longer valid, which is pretty much the same thing as using a reference beyond its lifetime; see GotW #18 for details about the accidental use of invalid iterators.

呼び出し元のコードがこのようなことをしていて、参照をその有効期間を超えて使っていると、そのバグはたいてい、時々しか発生せずにとても解析のしづらいものとなります。標準ライブラリでプログラマが犯すもっとも一般的な失敗は、イテレータがもう有効でないのに使ってしまうことですが、参照をその有効期間を超えて使ってしまうというのはそれととても良く似ています。誤って無効なイテレータを使ってしまうことの詳細について GotW #18 を見てください。

Summary まとめ


There are some other optimization opportunities. Ignoring these for now, here is one possible corrected version of find_addr which fixes the unnecessary temporaries. To avoid a possible conversion in the employee/string comparison, we’ll assume there’s something like an employee::name() function and that .name() == name has equivalent semantics.

他にもいくつか最適化できるところがあります。今はそれは無視して、不要な一時オブジェクトを直したバージョンの find_addr の一例をお見せします。employee と string の比較における変換を避けるために、employee::name() のような関数があって .name() == name が等価なセマンティクスを持っていると仮定します。

Note another reason to prefer declaring local variables with auto: Because the list parameter is now const, calling begin and end return a different type—not iterators but const_iterators—but auto naturally deduces the right thing so you don’t have to remember to make that change in your code.

auto を使ってローカル変数を宣言するべきであるもう一つの理由:list 引数は const になりましたので begin と end の呼び出しは違う型を返すようになりました。iterator 型ではなく const_iterator 型です。しかし auto は自然に正しい型を推測しますので、その部分について忘れずにコードを変更する必要がありません。

string find_addr( const list<employee>& emps, const string& name ) {
    for( auto i = begin(emps);  i != end(emps); ++i ) {
        if( i->name() == name ) {
            return i->addr;
        }
    }
    return "";
}

Acknowledgments 謝辞

Thanks in particular to the following for their feedback to improve this article: “litb1,” Daan Nusman, “Adrian,” Michael Marcin, Ville Voutilainen, Rick Yorgason, “kkoehne,” and Olaf van der Spek.

この記事をより良くするための以下の各位からのフィードバックに対し、特に感謝する: “litb1,” Daan Nusman, “Adrian,” Michael Marcin, Ville Voutilainen, Rick Yorgason, “kkoehne,” そして Olaf van der Spek。

mruby on Tizen 2.2 beta

Tizen プロジェクトがキャンセルされたとか何とかいう噂がまことしやかに囁かれているようですが、Tizen は今のところ元気です。何事もなかったかのように淡々とプロジェクトは進行しています。

さて、Tizen SDK 2.2 beta もリリースされたことですので、さっそく mruby をビルドして動かしてみました。

build_config.rb に以下の内容を追加します。

といっても、前回の2.1の時からの変更点は rootstrap のディレクトリ名がちょっと変わったくらいです。

- TIZEN_GCC_I386_EMULATOR_BASE = "#{TIZEN_SDK}/platforms/tizen2.1/rootstraps/tizen-emulator-2.1.native"
+ TIZEN_GCC_I386_EMULATOR_BASE = "#{TIZEN_SDK}/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native"

- TIZEN_GCC_ARM_DEVICE_BASE = "#{TIZEN_SDK}/platforms/tizen2.1/rootstraps/tizen-device-2.1.native"
+ TIZEN_GCC_ARM_DEVICE_BASE = "#{TIZEN_SDK}/platforms/tizen2.2/rootstraps/tizen-device-2.2.native"


実行してみた結果:

(host)$ cd mruby
(host)$ ./minirake
(host)$ sdb -e root on
(host)$ sdb -e push build/tizen-x86/ /opt/apps/mruby/
(host)$ sdb -e shell
sh-4.1# /opt/apps/mruby/bin/mruby -e 'system "cat /etc/tizen-release"'
Tizen release 2.2.0 (Tizen)

今日から使える! 液晶マイコンボード付きmruby学習キット EAPL-Trainer mruby

今日から使える! 液晶マイコンボード付きmruby学習キット EAPL-Trainer mruby


Arduino イーサネットシールド

Arduino イーサネットシールド


Rubyプログラミング入門

Rubyプログラミング入門


たのしいRuby 第3版

たのしいRuby 第3版

Ubuntu 12.04 で特定のポインティングデバイスからの入力だけマッピングを変更する方法

.Xmodmap を使ってマウスのボタンのマッピングを変更すると、すべてのポインティングデバイスからの入力を一律で変更してしまいます。

たとえば、トラックパッドが付いているノートパソコンに USB マウスもつないでいる状態だと、ポインティングデバイスが 2 つある状態になりますが、.Xmodmap で書いた pointer 設定は両方のデバイスからの入力に適用されてしまいます。

そうなると、「トラックパッドは natural scrolling にしたいけどマウスは従来通りにしたい」というような希望があったとしたらそれが実現できないことになってしまいます。

そこで xinput コマンドを使用します。

まずは

xinput list

で自分の PC に接続されている入力デバイスの一覧を取得します。

そしてその中からターゲットとなるポインティングデバイスの id を見つけます。

つぎに以下のようなコマンドを入力します。

xinput set-button-map <ID> 1 2 3 4 5 6 7 8 9 10 11 12


<ID> には xlinput list で調べた ID を入れます。
その後ろの 1 〜 12 はボタンの設定です。(ホイールを回した時も、回転方向に応じたボタンが押されていることになっているようです)

私のマウスの場合は 4 と 5 がスクロールの上下に対応していたので、そこを入れ替えれて natural scrolling が実現できました。

GotW #1 Solution: Variable Initialization – or Is It?(勝手訳:変数の初期化-もしくは?)

前回の投稿から少し間が開いてしまいましたが、第1回めの GotW の翻訳です。

例によって原文著者(Herb Sutter 氏)の許可は得ていませんし、私の英訳がヒドいクオリティである(用語の統一がとれていないとか、誤訳が含まれているとか)かもしれませんのでそこのところはご理解いただければと思います。


原文:http://herbsutter.com/2013/05/09/gotw-1-solution/

This first problem highlights the importance of understanding what you write. Here we have a few simple lines of code—most of which mean something different from all the others, even though the syntax varies only slightly.

この最初の問題は、あなたが書くものを理解することの重要性を浮き彫りにします。数行のシンプルなコードを提示しますが、ほとんどの行はたとえシンタックス上の違いがわずかだとしても他のすべての行と何かしら異なる意味を持ちます。

Problem 問題

JG Question 見習いグルへの質問

1. What is the difference, if any, among the following?
1. 以下のうち、違いがあるとしたらそれは何か?

widget w;                   // (a)
widget w();                 // (b)
widget w{};                 // (c)
widget w(x);                // (d)
widget w{x};                // (e)
widget w = x;               // (f)
widget w = {x};             // (g)
auto w = x;                 // (h)
auto w = widget{x};         // (i)
Guru Questions

グルへの質問

2. What do each of the following lines do?
2. 以下のそれぞれの行は何をするか?

vector<int> v1( 10, 20 );   // (a)
vector<int> v2{ 10, 20 };   // (b)


3. Besides the cases above, what other benefits are there to using { } to initialize objects?
3. 上記のケース以外で、オブジェクトを初期化するために {} を使うことにどのような効能があるか?


4. When should you use ( ) vs. { } syntax to initialize objects? Why?
4. オブジェクトを初期化するために {} ではなく () を 使うべきときはいつか?それはなぜか?



Solution 解答

This puzzle demonstrates several things:

  • The difference between default initialization, direct initialization, copy initialization, and list initialization.
  • The difference between using ( ) and using { } for initialization.
  • A red herring that isn’t initialization at all, and which modern C++ entirely avoids.

この問題はいくつかのことを明らかにします:

  • デフォルト初期化、ダイレクト初期化、コピー初期化、およびリスト初期化の違い
  • 初期化に () を使うことと {} を使うことの違い
  • 全くもって初期化ではないという罠と、モダンな C++ がそれを完全に回避していること

But, most important of all: If you stick to two simple Guidelines, which we’ll cover in #4, you can ignore most of these cases and the rules are pretty simple and deliver efficient performance by default.

しかし最も重要なのは、あなたが #4 でカバーされる 2 つのシンプルなガイドラインさえ守っていれば、これらのケースのほとんどを無視することができるということと、ルールはとてもシンプルであるということと、デフォルトで効率面でのパフォーマンスをもたらしてくれるということです。


1. What is the difference, if any, among the following?
1. 以下のうち、違いがあるとしたらそれは何か?

Let’s consider the cases one by one.

それぞれのケースを1つずつ考えてみましょう。

(a) is default initialization.
(a) はデフォルト初期化。

widget w;                   // (a)

This code declares a variable named w, of type widget. For most types, it is initialized using the default constructor widget::widget().

このコードは widget 型の w という名前の変数を宣言します。ほとんどの型において、デフォルトコンストラクタ widget::widget() を使って初期化されます。


Note that w is not initialized and contains garbage values if widget happens to be a built-in type like int, or a simple “int-like” class type with what’s called a “trivial” default constructor—a type that relies on the compiler-generated default constructor, has no virtual functions or virtual base classes or data member initializers, and all its bases and members satisfy the same restrictions.

widget が int のような組み込み型である場合、もしくはシンプルな "int 風" クラス型である場合、w は初期化されずゴミの値を持つということに注意してください。ここでいう "int 風" クラス型とは、"trivial" デフォルトコンストラクタをもち、コンパイラの生成するデフォルトコンストラクタに依存し、仮想関数や仮想基底クラスやデータメンバイニシャライザを持たず、そのすべての基底クラスとメンバが同じ制約を満たすものです。

(b) is a “vexing” red herring, now mostly a historical curiosity.
(b) はウザい罠であり、現時点ではほとんど歴史的な珍しい存在です。

widget w();                 // (b)


This is a pre-modern C++ pitfall: At first glance, it may look like just another variable declaration calling a default constructor widget::widget(); in reality, thanks to a grammar ambiguity, it’s a function declaration for a function named w that takes no parameters and returns a widget object by value. (If you can’t see this at first, consider that the above code is no different from writing something like int f(); which is clearly a function declaration.)

これは前近代的 C++ の落とし穴です。一見、デフォルトコンストラクタ widget::widget() を呼んでいる他の変数宣言と同じように見えます。実際には、文法の曖昧さのため、これは w という名前で引数をとらず widget オブジェクトを値で返す関数の宣言です。(もし最初はそう見えなかったとしても、上記のコードは int f(); のような明らかな関数宣言と何も違いがないということを考えてみてください)

Lest you think “aw, but those ( ) parentheses are redundant, it’s the programmer’s own fault for not just writing widget w; there!”, note that the same problem arises in those occasional cases where you think you’re initializing a variable with temporary objects:

ここであなたが「あぅ、でもその () は冗長だから、それは widget w; って書かなかったプログラマの過失だよね!」と考えるといけないので、もう一つの例をお見せします。これはテンポラリオブジェクトで変数が初期化されると考えられるかもしれませんが同じ問題が起こるケースです。

// 同じ問題(gadget と doodad は型)
//
widget w( gadget(), doodad() );  // 落とし穴: 変数宣言ではない

Scott Meyers long ago named this “C++’s most vexing parse,” because the standard resolves the parsing ambiguity by saying: “if it can be a function declaration, it is.”
スコット・メイヤーズはずっと昔、これを "C++ の最もウザいパース" と呼びました。C++ 標準はパース時の曖昧さについて、こう言って解決しているからです:"もしそれが関数宣言でありうるなら、それは関数宣言である"


The good news is that this is now mostly a historical curiosity, not something you should encounter in new code, because C++11 removed this pitfall. Note that C++11 does not change the meaning of the code—C++11 has great backward compatibility with C++98, including that this ambiguity still has the same meaning it always had. Rather, C++11 solves this by providing a syntax that supersedes case (b) in nearly all cases, so that we don’t need to ever fall into this pit anymore:

良い知らせは、これはすでに歴史的に珍しいものとなっていて、あなたが新しいコードを書いている時に出会うべきものではないということです。C++ はこの落とし穴を取り除きました。といっても、C++11 はそのコードの意味を変えてはいないことに注意してください。C++11 は C++98 に対し素晴らしい後方互換性を持っています。この曖昧さについてもこれまでと同じ意味を持っています。C++11 はほとんどすべてのケースでケース (b) に取って代わるシンタックスを提供することでこれを解決します。これでもう私たちはこの落とし穴にこれ以上ハマる必要はなくなるのです:

(c) is non-vexing and clear.
(c) はウザくないし明快。

widget w{};                 // (c)


Here we have the first reason to prefer { } to ( ): For any class type widget, line (c) does the “best parts” of (a) and (b)—it always initializes the variable, and is never ambiguous with a function declaration. No vex, no fuss, no muss.

これが () よりも {} を好むべき第一の理由です。いかなるクラス型 widget に対しても、行 (c) は (a) と (b) の "良いとこ取り" をします。常に変数を初期化し、関数宣言と曖昧ではありません。ウザくないし、面倒なことは何もありません。

“Aha, but wait, it’s not that simple!” someone might object. “What if widget has a constructor that takes a std::initializer_list? Those are greedy (preferred), so if widget has one of those wouldn’t this call that?”

"アハ、でも待って、そんなにシンプルじゃないよ!" 誰かが異議を唱えるかもしれません。"widget がstd::initializer_list を取るコンストラクタを持っていたらどう?そいつは優先されるから、widget がそれを持ってたらそっちが呼ばれるんじゃないの?"


The answer is no, this really is just as simple as it looks, because the standard is explicit that an empty { } list means to call the default constructor if available. However, it’s good to be aware of initializer_lists, so let’s talk about those next.

答えは No です。これは見たとおりシンプルです。標準には、空の {} リストはデフォルトコンストラクタがあればそれを呼ぶと明示されているからです。しかしながら、initializer_list に注意するのはいいことです。というわけで次はそれについて話しましょう。

(d) and (e) are direct initialization.
(d) および (e) はダイレクト初期化。

Now let’s consider cases where we actually initialize w from some existing variable:

今度は w を何らかの既存の変数から初期化する場合を考えましょう:

widget w(x);                // (d)
widget w{x};                // (e)


Assuming x is not the name of a type, these are both direct initialization. That’s because the variable w is initialized “directly” from the value of x by calling widget::widget(x). If x is also of type widget, this invokes the copy constructor. Otherwise, it invokes a converting constructor.

x は型の名前ではないとすると、両方ともダイレクト初期化です。widget::widget(x) を呼ぶことで x の値から w が "直接" 初期化されるからです。x も widget 型の変数であるとするならば、これはコピーコンストラクタを起動します。そうでなければ変換コンストラクタを起動します。


However, note that the syntax {x} creates an initializer_list. If widget has a constructor that takes an initializer_list, that constructor is preferred; otherwise, if widget has a constructor that takes whatever type x is (possibly with conversions), that constructor is used.

しかしながら、シンタックス {x} は initializer_list を生成することに注意してください。widget が initializer_list を取るコンストラクタを持っている場合、そのコンストラクタが優先されます。それ以外の場合、widget が(変換を伴ったとしても)x の型を取るコンストラクタを持っているなら、そのコンストラクタが使用されます。


There are two major differences that make (e) superior to (d): First, like (c), syntax (e) is unambiguous and avoids the vexing parse. If x is a type name, then (d) is a function declaration even if there is also a variable named x in scope (see above), whereas (e) is never a function declaration.

(d) よりも (e) が優れている2つの大きな違いがあります:一つ目は、(c) と同様、シンタックス (e) は曖昧ではなく、ウザいパースを回避します。x が型の名前である場合、(d)は関数宣言になってしまいます。x という名前の変数がスコープ内にあったとしてもです(上記を参照)。それに対し、(e) は関数宣言になることはありません。


Second, syntax (e) is safer because it does not allow narrowing (a.k.a. “lossy”) conversions that are otherwise allowed for some built-in types. Consider:

2つ目に、シンタックス (e) はより安全です。ナローイング(narrowing) (データ損失を伴う) を許していないからです。

int i1( 12.345 );           // ok: .345 は捨てられてしまいます。いずれにせよ好ましくありません
int i2{ 12.345 };           // error: データ損失を伴う暗黙のナローイングが起こりうる


(f) and (g) are copy initialization and copy list initialization.
(f) と (g) はコピー初期化とコピーリスト初期化

This brings us to our final two non-autocases:

これは auto を使っていない残り2つのケースです:

widget w = x;               // (f)


This is called “copy initialization.” Conceptually, the variable w is initialized using widget‘s move or copy constructor, possibly after calling another function to convert the argument implicitly (explicit conversions won’t be invoked here).

これは"コピー初期化"と呼ばれます。概念的には、変数 w は widget のムーブコンストラクタかコピーコンストラクタを使って初期化されます。場合によっては引数を暗黙的に変換するための他の関数を呼んだ後でかもしれません(明示的変換はここでは起動しません)。

Common Mistake: This is always initialization; it is never assignment, and so it never calls T::operator=(). Yes, I know there’s an “=” character in there, but don’t let that throw you — that’s just a syntax holdover from C, not an assignment operation.

ありがちな間違い:これは常に初期化です。代入ではありません。T::operator=() を呼び出しもしません。そう、”=” の文字がそこにあるのにもかかわらずです。これは C から持ち越されたただの文法であり、代入操作ではありません。

Here are the semantics:

セマンティクスはこうです:

If x is of type widget, line (f) means the same as (d) widget w(x); except that explicit constructors cannot be used. It’s guaranteed that only a single constructor is called.

x が widget 型である場合、行(f) は (d) widget w(x); と同じ意味になります。ただし、explicit コンストラクタが使われることはありません。単一のコンストラクタのみが呼び出されることは保証されています。


If x is of some other type, conceptually the compiler first implicitly converts x to a temporary widget object, then move-constructs w from that temporary rvalue, using copy construction as “the slow way to move” as a backup if no better move constructor is available. Assuming that an implicit conversion is available, (f) means the same as widget w( widget(x) );.

x が他の何かの型である場合、概念的にはコンパイラはまず暗黙的に x をテンポラリな widget 型のオブジェクトに変換し、それからそのテンポラリな rvalue から w をムーブコンストラクトします。もしちょうど良いムーブコンストラクタがない場合、バックアップとして "ムーブするための遅い方法" としてコピーコンストラクションが使われます。暗黙の変換があるならば、(f) は widget w(widget(x)); と同じになります。


Note that I said “conceptually” a few times above. That’s because practically compilers are allowed to, and routinely do, optimize away the temporary and, if an implicit conversion is available, convert (f) to (d), thus optimizing away the extra move operation. However, even when the compiler does this, the widget copy constructor must still be accessible, even if is not called—the copy constructor’s side effects may or may not happen, that’s all.

上記で何度か "概念的に" といったことに注意してください。”実際的には” コンパイラはそのテンポラリを最適化して取り除くことが許されていますし、普通のコンパイラはそうしますし、もし暗黙の変換があれば (f) を (d) に変換しますので、そのムダなムーブ操作が最適化されて取り除かれます。しかしながら、コンパイラがそうするからといって、widget コピーコンストラクタはアクセス可能でなければなりません。たとえ呼ばれることがなく、コピーコンストラクタの副作用があろうがなかろうが。以上。


Now note the related syntax that adds “=“:

さて、今度は関連するシンタックスとして "=" を加えたものに着目しましょう。

widget w = {x};             // (g)


This is called “copy list initialization.” It means the same as widget w{x}; except that explicit constructors cannot be used. It’s guaranteed that only a single constructor is called.

これは "コピーリスト初期化" と呼ばれます。これは widget w{x}; と同じ意味です。ただし、explicit コンストラクタは使われません。単一のコンストラクタのみが呼び出されることが保証されています。

(h) and (i) are also copy initialization, but simpler.
(h) と (i) もコピー初期化ですが、よりシンプル

auto w = x;                 // (h)
auto w = widget{x};         // (i)

The semantics are just like (f) and (g), except simpler to teach, learn, and use because using auto guarantees the right-hand expression’s type will be deduced exactly. Note that the (i) syntax works fine for both implicit and explicit conversions.

セマンティクスは (f) や (g) と同様ですが、教えたり習ったり使ったりするにはシンプルな点が異なります。auto を使っているので右辺の式の型が推定されることが保証されるからです。(i) シンタックスは暗黙のおよび明示的な変換が共にうまく働くことに注意してください。


Line (h) means the same as (d), type_of_x w(x);. Only a single copy constructor is called. This is guaranteed to stay true as the program evolves: Because line (h) does not commit to an explicit type, it is guaranteed to be both maximally efficient because there can be no conversion involved, and maximally robust under maintenance as the type of w “auto”-matically tracks the type of x which may change as the program is maintained.

行 (h) は (d) と同じ意味で、<xの型> w(x); です。一度だけコピーコンストラクタが呼び出されます。これはプログラムが変更されても真であることが保証されます。行 (h) は明示的な型を確定しておらず、変換が発生しないので最大限に効率的であることと、プログラムが保守されて x の型が変わっても w の型が自動的に追随するので最大限にロバストであるからです。

Line (i) is the most consistent spelling when you do want to commit to a specific type and explicitly request a conversion if needed, and once again the { } syntax happily avoids lossy narrowing conversions. In practice on most compilers, only a single constructor is called—similarly to what we saw with (f) and (g), conceptually there are two constructor calls, a converting or copy constructor to create a temporary widget{x} followed by a move to move it to w, but compilers routinely elide the latter.

行 (i) は、特定の型を確定したい場合に最も一貫性のある書き方です。必要に応じて明示的な型変換が行われ、なおかつデータ損失を伴うナローイング変換を避ける {} が使われています。実際にはほとんどのコンパイラは、(f) や (g) で見てきたのと同様、コンストラクタを一度だけ呼び出します。概念的には2回のコンストラクタ呼び出し - widget{x} の一時オブジェクトを生成するための変換コンストラクタかコピーコンストラクタと、wにそれをムーブするためのムーブコンストラクタ - がありますが、コンパイラはお決まりのパターンとして後者を取り除きます。

In general, I recommend that you try out these two forms, and increasingly prefer using them as you grow comfortable with them. I’m at the point where I’m now inclined to write virtually all of my local variable declarations this way. (I know some of you will be skeptical about this broad claim—more on “the auto question” in another GotW.)

一般的に、これらの2つの形をお試しになることをお勧めします。これらを好んで使うことが多くなるに従い、より満足度も増加することでしょう。私自身、ローカル変数を宣言するほとんどすべての箇所でこの方法を使うようになりました。(この口幅ったい言い方に対して懐疑的な方もいるかもしれません。"auto" についての GotW をお楽しみに)


2. What do each of the following lines do?
2. 以下の各行は何をするか?

In the Question 2 code, we’re creating a vector and passing the arguments 10 and 20 to its constructor—in the first case as ( 10, 20 ) and in the second case as { 10, 20 }.

質問2のコードでは、vector を生成して引数 10 と 20 をそのコンストラクタに渡しています。1つ目では (10, 20) として、2つ目では {10,20} として。

Both will call a constructor, but which one(s)? Well, vector has several constructors that can take two parameters, but only two could be correctly called with the parameters 10 and 20. Ignoring defaulted optional allocator parameters for simplicity, the two constructors are:

両方ともコンストラクタを呼び出します。ではどのコンストラクタを呼び出すのでしょう?ええと、vector は 2 つの引数を受け取るいくつかのコンストラクタを持っていますが、引数 10 と 20 で正しく呼び出されるものは 2 つだけです。デフォルトで指定されるオプションのアロケータ引数は、簡素化のために無視します。その2つのコンストラクタとは:

vector( size_t n, const int& value );    // A: value の n 個のコピー
vector( initializer_list<int> values );  // B: values のコピー


There are two simple C++ rules that tell us which one will be called for the code in question:

  • The syntax { /*…*/ } used in an expression context gives you an initializer_list.
  • Constructors that take an initializer_list are preferred over other constructors, and so can hide other constructors that might otherwise be viable.

2つのシンプルな C++ のルールが、質問のコードに対してどのコンストラクタが呼ばれるのかを教えてくれます。


Armed with those two tidbits, the answer is simple:

この2つで武装して、答えはシンプルに:

vector<int> v1( 10, 20 );    // (a) A が呼ばれる: 値 20 のコピー が 10 個
assert( v1.size() == 10 );

vector<int> v2{ 10, 20 };    // (b) B が呼ばれる: 値 10 と 20
assert( v2.size() == 2 );


3. Besides the cases above, what other benefits are there to using { } to initialize objects?
3. 上記のケース以外で、オブジェクトを初期化するために {} を使うことにどのような効能があるか?

For one thing, it’s called “uniform initialization” because it’s, well, uniform—the same for all types, including aggregate structs and arrays and std:: containers, and without the “vexing parse” annoyance:

一つとして、”単一形式(uniform)初期化" があります。それは、構造体や配列や std:: コンテナを含むすべての型に対して同じ形式が使えて、しかもあの "ウザいパース" が起こりません。

struct mystruct { int x, y; };

// C++98
rectangle w( origin(), extents() );       // おっと、ウザいパース
complex<double> c( 2.71828, 3.14159 );
mystruct        m = { 1, 2 };
int             a[] = { 1, 2, 3, 4 };
vector<int>     v;                              // 困った、初期化するには
for( int i = 1; i <= 4; ++i ) v.push_back(i);   //   もっとコードが必要だ

// C++11 (注意: "=" は必須ではない)
rectangle       w   = { origin(), extents() };
complex<double> c   = { 2.71828, 3.14159 };
mystruct        m   = { 1, 2 };
int             a[] = { 1, 2, 3, 4 };
vector<int>     v   = { 1, 2, 3, 4 };

And note that this isn’t just an aesthetic issue. Consider writing generic code that should be able to initialize any type… and while we’re at it, let’s gratuitously use perfect forwarding as an example:

これは美的問題だけにとどまりません。どんな型でも初期化できるべきであるようなジェネリックなコードを書くことを考えてみましょう。... 忙しいのでとにかくパーフェクトな forwarding を例として取り上げましょう:

template<typename T, typename ...Args>
void forwarder( Args&&... args ) {
    // ...
    T local = { std::forward<Args>(args)... };
    // ...
}
forwarder<int>            ( 42 );                  // ok
forwarder<rectangle>      ( origin(), extents() ); // ok
forwarder<complex<double>>( 2.71828, 3.14159 );    // ok
forwarder<mystruct>       ( 1, 2 );                // ok {} のおかげ
forwarder<int[]>          ( 1, 2, 3, 4 );          // ok {} のおかげ
forwarder<vector<int>>    ( 1, 2, 3, 4 );          // ok {} のおかげ


The last three lines would not be legal if forwarder used ( ) initialization syntax internally.

最後の3行は forwarder が () 初期化シンタックスを内部的に使用していると、成立しません。


The new { } syntax works pretty much everywhere, including to initialize members:

新しい {} シンタックスはどこででもうまく動きます。メンバの初期化のときも:

widget::widget( /*...*/ ) : mem1{init1}, mem2{init2, init3} { /*...*/ } 


And, as icing on the take, it’s often just plain convenient to pass function arguments, or return a value, without a type-named temporary:

関数の引数に渡したり、値を返したりするときに、一時オブジェクトの型名を書かなくて良くなるので素直に便利です。

void draw_rect( rectangle );

draw_rect( rectangle(origin, selection) );         // C++98
draw_rect({ origin, selection });                  // C++11

rectangle compute_rect() {
    // ...
    if(cpp98) return rectangle(origin, selection);  // C++98
    else      return {origin, selection};           // C++11
}


4. When should you use ( ) vs. { } syntax to initialize objects? Why?
4. オブジェクトを初期化するために {} ではなく () を 使うべきときはいつか?それはなぜか?


Here’s the simple guideline:

シンプルなガイドライン:


Guideline: Prefer to use initialization with { }, such as vector v = { 1, 2, 3, 4 }; or auto v = vector{ 1, 2, 3, 4 };, because it’s more consistent, more correct, and avoids having to know about old-style pitfalls at all. In single-argument cases where you prefer to see only the = sign, such as int i = 42; and auto x = anything; omitting the braces is fine. …

ガイドライン:{} による初期化を好んで使え。たとえばvector v = { 1, 2, 3, 4 };もしくはauto v = vector{ 1, 2, 3, 4 };のように。より一貫性があり、より正しく、古いスタイルの落とし穴についての知識を全く持たなくてもよくなる。引数が1つだけのケースでは、= 記号を使いたくなるが、この場合はint i = 42;やauto x = anything;のように {} を使わなくても構わない。


That covers the vast majority of cases. There is only one main exception:

これはほとんどのケースをカバーします。1つだけの主要な例外は:


… In rare cases, such as vector v(10,20); or auto v = vector(10,20);, use initialization with ( ) to explicitly call a constructor that is otherwise hidden by an initializer_list constructor.

...レアなケースとして、vector v(10,20);やauto v = vector(10,20);のように () による初期化を使う。そうしなければ、初期化リストコンストラクタによって隠されてしまうコンストラクタを明示的に呼び出すことができない。

However, the reason this should be generally “rare” is because default and copy construction are already special and work fine with { }, and good class design now mostly avoids the resort-to-( ) case for user-defined constructors because of this final design guideline:

しかしながら、これが一般的には "レア" なのは、デフォルトコンストラクタとコピーコンストラクタがすでに特別であり、{} でうまく動くからで、よいクラスのデザインはいまやこの最後のデザインガイドラインのためにユーザ定義のコンストラクタのために () を使うことをほとんど避けています。


Guideline: When you design a class, avoid providing a constructor that ambiguously overloads with an initializer_list constructor, so that users won’t need to use ( ) to reach such a hidden constructor.

ガイドライン:クラスをデザインするとき、initializer_list コンストラクタで曖昧にオーバーロードするようなコンストラクタを提供することを避け、ユーザがそのような隠されるコンストラクタを呼び出すために () を使う必要がないようにする。


Acknowledgments
謝辞

Thanks in particular to the following for their feedback to improve this article: Michal Mocny, Jay Miller, “Alexey,” “praetorian20,” Francisco Lopes, “Neil,” Daryle Walker.

この記事をより良くするための以下の各位からのフィードバックに対し、特別に感謝する:Michal Mocny, Jay Miller, “Alexey,” “praetorian20,” Francisco Lopes, “Neil,” Daryle Walker

Exceptional C++―47のクイズ形式によるプログラム問題と解法 (C++ in‐Depth Series)

Exceptional C++―47のクイズ形式によるプログラム問題と解法 (C++ in‐Depth Series)

  • 作者: ハーブサッター,浜田光之,Harb Sutter,浜田真理
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/11
  • メディア: 単行本
  • 購入: 9人 クリック: 134回
  • この商品を含むブログ (62件) を見る

Exceptional C++ Style―40のクイズ形式によるプログラム問題と解法=スタイル編 (C++ in‐Depth Series)

Exceptional C++ Style―40のクイズ形式によるプログラム問題と解法=スタイル編 (C++ in‐Depth Series)

  • 作者: ハーブサッター,浜田光之,Herb Sutter,浜田真理
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2006/09
  • メディア: 単行本
  • 購入: 3人 クリック: 32回
  • この商品を含むブログ (29件) を見る

More Exceptional C++ さらに40のクイズ形式によるプログラム問題と解法 (C++ In‐Depth Series)

More Exceptional C++ さらに40のクイズ形式によるプログラム問題と解法 (C++ In‐Depth Series)

  • 作者: ハーブサッター,Herb Sutter,浜田光之,浜田真理
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2008/11/05
  • メディア: 単行本(ソフトカバー)
  • 購入: 2人 クリック: 32回
  • この商品を含むブログ (19件) を見る

複数のターミナル間で bash のヒストリを共有する方法

Guake とか Terminator とか iTerm とか Console2 とかでタブを開きまくっていると、あっちのタブで入力したコマンドがこっちのタブにはヒストリとして出てこない!ムキーっってなりますね。特に超絶かっこいいワンライナーを書いた時にそれを再利用するためにどのタブで打ったか探しまわったりしている時には、ハイテクなんだかローテクなんだかよくわからなくて惨めな気持ちになりますね。

だいぶ前に、この問題の解決を試みようとしたときはなぜか全然うまく行かなくて挫折した記憶があるのですが、今日改めてぐぐってみたら一発で解決しました。

$ export PROMPT_COMMAND='history -a; history -r'

これだけです。
これを ~/.bashrc の片隅にでも忍ばせておくだけで幸せになれること請け合いです。


以下、ちょっと解説。

まず、bash の組込み変数(シェル変数)である PROMPT_COMMAND に値を設定しておくと、bash はプロンプトを表示する直前に毎回そのコマンドを実行してくれるようです。

そこに history -a と history -r を実行するように指定しています。

history -a はそのセッションで直前に実行したコマンドをヒストリ保存ファイルに追加するためのコマンドです。
history -r はヒストリ保存ファイルに保存されている内容をロードするためのコマンドです。

ですので、あるセッションで打ったコマンドがリアルタイムにすべてのセッションのヒストリに反映されるわけではありませんが、大抵の場合は意識せずともコマンド履歴がマージされながら更新されていくことになるので問題ないでしょう。

入門bash 第3版

入門bash 第3版


bashクックブック

bashクックブック