C++ Coding Standards

C++ Coding Standards―101のルール、ガイドライン、ベストプラクティス C++ Coding Standards―101のルール、ガイドライン、ベストプラクティス
浜田 光之、ハーブ サッター 他 (2005/10)
ピアソンエデュケーション
この商品の詳細を見る

EffectiveシリーズやExceptionalシリーズのトピックスを集めて簡潔にまとめたような書籍。

全てのC++プログラマが手元に置いて、日常的に読み返して欲しい一冊。Exceptional C++Herb Sutter氏とModern C++ DesignAndrei Alexandrescu氏の共著によるC++のCoding Standardsです。

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

RAIIイディオム

Problem
『後始末』を確実に行うには、どのようにすれば良いでしょうか?

Solution
何らかの処理を行う前に初期化を行い、処理が終わった後には『後始末』が必要となることがしばしばあります。標準ライブラリで言えばstd::fopen/std::fcloseの例などが挙げられます。
void func(const char* file)
{
  std::FILE* fp = std::fopen(file, "r");
  
  // 何らかの処理を行う
  
  std::fclose(fp);
}
さて、上記のコードにはいくつか問題点があります。

問題の一つはメンテナンス性の悪さです。例えば、処理の途中のreturnステートメントの前に必ず、std::fcloseを呼び出すという『後始末』を記述する責務がプログラマに課せられます。これでは修正に対して、とても脆弱なコードと言えます。

次に、例外安全性に関する問題があります。例えば、処理の途中で例外が発生した場合に『後始末』の実行が省かれてしまい、リソースリークが発生してしまいます。

それでは、どのような解決策があるでしょうか。最もエレガントな解決策は、コンストラクタとデストラクタを用いてリソースを管理するテクニックです。
class FileResource {
public:
  explicit FileResource(std::FILE* fp) : fp_(fp) {}
  ~FileResource() { if (fp_) std::fclose(fp_); }
  std::FILE* get() { return fp_; }
private:
  std::FILE* fp_;
};

void func(const char* file)
{
  FileResource fileResource(std::fopen(file, "r"));
  
  // 何らかの処理を行う
}
リソースを管理する責務をクラスオブジェクトに託すことで、オブジェクトのライフタイムが終わる時に、そのオブジェクトが自働的に『後始末』を行ってくれます。

これがResource Acquisition Is Initialization Idiomと呼ばれるイディオムです。

このRAIIイディオムはファイルのopen/closeに限らず、共有リソースのlock/unlockやnew/deleteなどの動的なメモリアロケーションなどに対しても有効です。その中でもnew/deleteに特化したものが、標準ライブラリのstd::auto_ptrやstd::tr1::shared_ptrに代表されるスマートポインタ(smart pointer)です。

関連記事
RAIIイディオム
RAIIイディオム - Part2

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

Modern C++ Design

Modern C++ Design―ジェネリック・プログラミングおよびデザイン・パターンを利用するための究極のテンプレート活用術 Modern C++ Design―ジェネリック・プログラミングおよびデザイン・パターンを利用するための究極のテンプレート活用術
アンドレイ アレキサンドレスク (2001/12)
ピアソンエデュケーション
この商品の詳細を見る

正誤表はこちら

C++はマルチパラダイムをサポートしたプログラミング言語であり、本書はジェネリック・プログラミングに関する書籍である。

ジェネリック・プログラミング以外のパラダイム(例えばオブジェクト指向)に関する書籍は多くあるがジェネリック・プログラミングに関する書籍(特に日本語の書籍)は極めて少なく、このAndrei Alexandrescu氏の著書はジェネリック・プログラミングの深遠を知る上でとても重要な書籍である。

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

STLコンテナにリファレンスを格納させる

Problem
std::vectorなどのSTLコンテナに格納されるオブジェクトの型にリファレンスを指定したい場合は、どのようにすれば良いでしょうか?

Solution
標準ライブラリのSTLコンテナに格納されるオブジェクトの型は、CopyConstructibleかつAssignableを満たしている必要があります。std::auto_ptrなどは、このコンテナ要件を満たしていないためコンテナに格納できません。リファレンスの場合も同様に、このコンテナ要件を満たさないためにコンテナに格納できません。
しかし、C++0xに含まれるテンプレートクラスstd::tr1::reference_wrapperを用いれば、CopyConstructible要件とAssignable要件を満たすリファレンスのラッパ型を具現化できます。
#include <iostream>
#include <algorithm>
#include <vector>
#include <tr1/functional>

int main()
{
  int object0 = 0;
  int object1 = 1;
  
  std::vector<std::tr1::reference_wrapper<int> > v;
  v.push_back(std::tr1::ref(object0));
  v.push_back(std::tr1::ref(object1));
  
  // コンテナの要素はオブジェクトのリファレンスなので、アドレスと値が等しい。
  std::cout << "0: object0(" << &object0 << ") = " << object0 << ", v[0](" << &v[0].get() << ") = " << v[0] << std::endl;
  std::cout << "1: object1(" << &object1 << ") = " << object1 << ", v[1](" << &v[1].get() << ") = " << v[1] << std::endl;
  std::cout << std::endl;
  
  // オブジェクトをswapすると、コンテナの要素の値もswapされる。
  std::swap(object0, object1);
  std::cout << "0: object0(" << &object0 << ") = " << object0 << ", v[0](" << &v[0].get() << ") = " << v[0] << std::endl;
  std::cout << "1: object1(" << &object1 << ") = " << object1 << ", v[1](" << &v[1].get() << ") = " << v[1] << std::endl;
  std::cout << std::endl;
  
  // コンテナの要素の値をswapすると、オブジェクトもswapされる。
  std::swap(v[0].get(), v[1].get());
  std::cout << "0: object0(" << &object0 << ") = " << object0 << ", v[0](" << &v[0].get() << ") = " << v[0] << std::endl;
  std::cout << "1: object1(" << &object1 << ") = " << object1 << ", v[1](" << &v[1].get() << ") = " << v[1] << std::endl;
  std::cout << std::endl;
  
  // コンテナの要素をswapすると、要素の位置がswapされる。
  std::swap(v[0], v[1]);
  std::cout << "0: object0(" << &object0 << ") = " << object0 << ", v[0](" << &v[0].get() << ") = " << v[0] << std::endl;
  std::cout << "1: object1(" << &object1 << ") = " << object1 << ", v[1](" << &v[1].get() << ") = " << v[1] << std::endl;
  std::cout << std::endl;
  
  return 0;
}
実行結果はこうなります。
0: object0(0xaf968430) = 0, v[0](0xaf968430) = 0
1: object1(0xaf96842c) = 1, v[1](0xaf96842c) = 1

0: object0(0xaf968430) = 1, v[0](0xaf968430) = 1
1: object1(0xaf96842c) = 0, v[1](0xaf96842c) = 0

0: object0(0xaf968430) = 0, v[0](0xaf968430) = 0
1: object1(0xaf96842c) = 1, v[1](0xaf96842c) = 1

0: object0(0xaf968430) = 0, v[0](0xaf96842c) = 1
1: object1(0xaf96842c) = 1, v[1](0xaf968430) = 0

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

Exceptional C++ Style

Exceptional C++ Style―40のクイズ形式によるプログラム問題と解法=スタイル編 Exceptional C++ Style―40のクイズ形式によるプログラム問題と解法=スタイル編
浜田 光之、ハーブ サッター 他 (2006/09)
ピアソンエデュケーション
この商品の詳細を見る

Herb Sutter氏のExceptional C++の続編です。

Exceptional C++の原著が1999年刊行ということで、C++が標準化されて間もないころの著書でしたが、こちらの原著は2004年刊行ということで、より洗練された内容になっています。

このHerb Sutter氏のExceptionalシリーズは、Scott Meyers氏のEffectiveシリーズと補間しあうような関係にあり、Effectiveシリーズと併せて全てのC++プログラマが読むべき書籍です。

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

Exceptional C++

Exceptional C++―47のクイズ形式によるプログラム問題と解法 Exceptional C++―47のクイズ形式によるプログラム問題と解法
浜田 光之、ハーブ サッター 他 (2000/11)
ピアソンエデュケーション
この商品の詳細を見る

Scott Meyers氏のEffective C++Effective STLの次に重要な書籍を挙げるならHerb Sutter氏のExceptionalシリーズです。

このExceptional C++は例外安全性について詳しく述べられています。例外安全性に関してはC++に限らず、例外をサポートする現代的なプログラミング言語の全てにおいて、注意を払う必要がある事柄だと思います。

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

仮想関数を用いないStrategyパターン

Problem
Strategyパターンは便利なデザインパターンですが、他の多くのデザインパターンと同様に実装には仮想関数を用いるのが一般的です。 しかし、様々な理由から、仮想関数を用いたくない場合があります。仮想関数を用いないStrategyパターンを実装してみてください。

Solution
デザインパターンのバイブルであるオブジェクト指向における再利用のためのデザインパターンによるとStrategyパターンとは、
アルゴリズムの集合を定義し、各アルゴリズムをカプセル化して、それらを交換可能にする。
とあります。
アルゴリズムを交換可能にすることができれば良いわけで、その実装方法として仮想関数を用いることが一般的となっています。 つまり実装方法として、仮想関数(実行時ポリモーフィズム)を用いることが唯一の手段ではありません。例えば、関数ポインタでも実装できそうです。 しかし、C++では関数ポインタを用いるよりも遥かにエレガントで柔軟な実装方法があります。

それはテンプレート(コンパイル時ポリモーフィズム)です。

関数ポインタは関数のシグネチャーが厳密に一致している必要がありますが、 std::tr1::function/std::tr1::bindを用いれば関数だけでなく、関数オブジェクトやメンバ関数を交換可能なアルゴリズムとして扱うことができます。
実装例はこうなります。
#include <iostream>
#include <sstream>
#include <tr1/functional>

struct ConcreteStrategyA {
  int operator()(char* argument) const
  {
    std::cout << "ConcreteStrategyA::operator()(const char* argument) : " << std::ends;
    
    int result = 0;
    std::stringstream(argument) >> result;
    return result;
  }
};

short ConcreteStrategyB(const char* argument)
{
  std::cout << "ConcreteStrategyB(char* argument) : " << std::ends;
  
  short result = 0;
  std::stringstream(argument) >> result;
  return result;
}

struct ConcreteStrategyC {
  unsigned short method(void* argument) const
  {
    std::cout << "ConcreteStrategyC::method(void* argument) : " << std::ends;
    
    unsigned short result = 0;
    std::stringstream(static_cast<const char*>(argument)) >> result;
    return result;
  }
};

class Context {
public:
  typedef std::tr1::function<int (char*)> function_type;
  typedef function_type::result_type      result_type;
  typedef function_type::argument_type    argument_type;

  explicit Context(function_type strategy = ConcreteStrategyA())
   : strategy_(strategy) {}

  result_type interface(argument_type n)
    { return strategy_(n); }

private:
  function_type strategy_;
};

int main()
{
  // デフォルト引数により関数オブジェクトを用いる
  Context contextA;
  std::cout << contextA.interface("100") << std::endl;
  
  // 関数を用いる
  Context contextB(ConcreteStrategyB);
  std::cout << contextB.interface("100") << std::endl;
  
  // メンバ関数を用いる
  Context contextC(std::tr1::bind(&ConcreteStrategyC::method,
                                  ConcreteStrategyC(),
                                  std::tr1::placeholders::_1));
  std::cout << contextC.interface("100") << std::endl;
  
  return 0;
}
実行結果はこうなります。
ConcreteStrategyA::operator()(const char* argument) : 100
ConcreteStrategyB(char* argument) : 100
ConcreteStrategyC::method(void* argument) : 100
Notes
1. Effective C++ : 35項 仮想関数の代わりになるものを考えよう
Effective C++ 原著第3版 Effective C++ 原著第3版
スコット・メイヤーズ (2006/04/29)
ピアソン・エデュケーション
この商品の詳細を見る

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

Effective STL

Effective STL―STLを効果的に使いこなす50の鉄則 Effective STL―STLを効果的に使いこなす50の鉄則
スコット メイヤーズ (2002/01)
ピアソンエデュケーション
この商品の詳細を見る

Scott Meyers氏のEffectiveシリーズのSTL本です。

Effective C++はC++全般を取り扱っていますがSTLに関する内容は僅かです。STLに関してはEffective STLとして独立した書籍にまとめられています。STLを使用するプログラマ(つまり全てのC++プログラマ)必読の一冊です。

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

« 前頁へ移動する  | HOME |  次頁へ移動する »

ブログ内検索


このサイト内ウェブ全体
この検索は「緑のgoo」を利用しています

カテゴリー

未分類 (0)
C++ (24)
Books (11)
Bookmarks (1)

最近のエントリ

移植性の高いコードを書くためには (02/16)
ハッシュコンテナ - Part3 (01/10)
ハッシュコンテナ - Part2 (10/29)
日本語によるC++0xに関する記事 (10/23)
foreach (08/03)

Books

C++
プログラミング
デザインパターン
オブジェクト指向

RSSフィード

最新記事のRSS
最新コメントのRSS
最新トラックバックのRSS

アーカイブ

2008年02月 (1)
2008年01月 (1)
2007年10月 (2)
2007年08月 (1)
2007年07月 (2)
2007年06月 (1)
2007年05月 (2)
2007年04月 (1)
2007年03月 (2)
2007年02月 (2)
2007年01月 (3)
2006年12月 (4)
2006年11月 (8)
2006年10月 (6)

連絡先

email.png

Amazon