BT

Herb Sutter氏の語る現代的C++プログラミングの基本

| 作者: Sergio De Simone フォローする 13 人のフォロワー , 翻訳者 吉田 英人 フォローする 0 人のフォロワー 投稿日 2014年10月26日. 推定読書時間: 4 分 |

原文(投稿日:2014/10/07)へのリンク

CppCon 2014でHerb Sutter氏が,現代的なC++プログラミングの基本的なイディオムに関する講演を行った。ここではその要約を紹介しよう。

氏も認めているように,C++は難しい言語である。しかしながら,すべてのプログラマにとって複雑ということではない。低レベルなコードやライブラリを扱う時のような,言語の最も難解な部分について考慮すべきなのは,ごく限られた少数のプログラマであって,他はそれを単に動作する"デフォルト"として使用することが可能なはずだ,と氏は言う。

代表的な例のひとつは 範囲forループの利用だ。次のような記述も可能だが,

for (auto i = begin(c); i != end(c); ++i) { ... }

最近のC++であれば,同じことをもっと簡単に

for (auto& e : c) { ... }

と記述できて,可読性も優れている。

ポインタ,参照,newとdelete

もうひとつ,氏が強く推奨するのは,低レベルのデータ構造内にカプセル化されるものを除いて,ポインタ変数*の所有やnewdeleteを使用しない,ということだ。unique_ptrを使用するか,共有が必要と分かっていればshared_ptrを用いるのが望ましい方法だと氏は言う。次のように簡単に記述すればよい。

auto p = make_unique<widget>();
auto q = make_shared<widget>();

make_uniquemake_sharedを使えば,deleteについて気にする必要もなくなる。

しかしながら,*&がなければリソースの使用量が大きくなる。この2つの最適なユースケースは,関数に渡すパラメータだ。本当のアンチパターンだと氏が考えるのは,パラメータ渡しに変数の参照カウントを使用することである。これはただ単にパフォーマンス問題の原因となるだけであり,ラッパオブジェクトの所有を譲渡する目的でのみ使用されるべきものだ。

ローカル変数の宣言にautoを使用する

autoキーワードは,現代的なC++の機能として最も重要なもののひとつだ,と氏は言う。autoは変数型を推論するためだけでなく,使用される型を特定するためにも使用することができる。次のような文を考えてみよう。


auto i = v.begin();

これによって,使用されている型が正確に推論される。次のような記述よりもはるかに簡単で,難しいことを考える必要もない。


vector::const_iterator i = v.begin();

ここでは特に,const_iteratorの利用も考慮しなくてはならない。

このような正確さがautoの最大のメリットだが,その価値は他の面にもある。

  • メンテナンス性: 関数の戻り値など,変更が容易に適応できるコードになる。

  • パフォーマンス: 正確な推論の帰結として,オブジェクトの初期化時などで,一時的オブジェクトが不用意に生成されないことも保証できる。

  • ユーザビリティ: ラムダのような特殊なコンテキストにおいて,autoは不可欠なファクタである。

  • 型利便性(Type Convenience): いくつかのキーワードを省略できる。

ただしC言語の配列を扱う場合や,移動が不能あるいは容易でない型など,autoを使用することのできないケースもいくつかある。


auto lock = lock_guard<mutext> { m };  //   エラー: 移動不可
auto ai = atomic<int>{}; // エラー: 移動不可
auto a = array<int,50>{}; // 正しいがコストが高い

パラメータの受け渡し

氏の講演では,パラメータの受け渡しの説明に多くの時間を割いていた。ここでのおもなポイントは,C++98のデフォルトが現在のC++でも引き続き有効であり,その出発点でもある一方で,右辺値の最適化によっていくつの機能が追加されているということだ。一例として,常に行うべきことは,


class employee {
   std::string name_;
public:
    void set_name(const std::string& name) { name_ = name; }    // C++98の標準的な記述方法
    void set_name(std::string&& name) noexcept { name_ = std::move(name); }    // 右辺値の最適化
};

その一方で氏は,値渡しは主としてコンストラクタで使用するように提案する。それ以外での値渡しは,右辺の最適化が可能ではあるが,名前付きのパラメータで渡す場合(つまり一時的オブジェクト)のパフォーマンス損失が大きくなる可能性があるからだ。

タプル

最後の提案は,戻り値としてのタプルの利用に関するものだ。


tie(iter, success) = myset.insert("Hello");
if (success) do_something_with(iter);

デフォルトやイディオムの強調に加えて,氏は,過度に難解なソリューションに到達することの多い,過度な考慮を避けるように述べている。すべての点において氏の提案は,プログラム言語がもっとも基本的なレベルで提供する機能の利用を原則とした上で,地道な試行錯誤によるパフォーマンス向上の労力に見合った成果が期待できる領域を慎重に選び出しているのだ。

この記事に星をつける

おすすめ度
スタイル

こんにちは

コメントするには InfoQアカウントの登録 または が必要です。InfoQ に登録するとさまざまなことができます。

アカウント登録をしてInfoQをお楽しみください。

あなたの意見をお聞かせください。

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする
コミュニティコメント

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする

ディスカッション

特集コンテンツ一覧

.NETの派生を理解する

Wayne Citrin 2018年7月18日 午前3時44分

ASP.NET Core - シンプルの力

Chris Klug 2018年6月4日 午前3時26分

InfoQにログインし新機能を利用する


パスワードを忘れた方はこちらへ

Follow

お気に入りのトピックや著者をフォローする

業界やサイト内で一番重要な見出しを閲覧する

Like

より多いシグナル、より少ないノイズ

お気に入りのトピックと著者を選択して自分のフィードを作る

Notifications

最新情報をすぐ手に入れるようにしよう

通知設定をして、お気に入りコンテンツを見逃さないようにしよう!

BT