Effective C++

Effective C++ 原著第3版 Effective C++ 原著第3版
スコット・メイヤーズ (2006/04/29)
ピアソン・エデュケーション
この商品の詳細を見る

エレガントなC++を書くためのスタイルガイドで、数多くあるC++書籍の中で最も重要であり、全てのC++プログラマが読まなければならない書籍が、このScott Meyers氏のEffective C++です。

第3版ではTR1(C++0x)やboostに関する内容を含んでおり、旧版を所有している方も読み直す必要がある。

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

Algorithm vs Loop

Problem
配列の総和を求める場合、Algorithmを用いるのとLoopを用いるのではどちらが良いでしょうか?
// Algorithm
int array[N];
int sum = std::accumulate(array, array+N, 0);
// Loop
int array[N];
int sum = 0;
for (int i = 0; i < N; ++i) {
  sum += array[i];
}
Solution
パフォーマンスとメンテナンス性の高いAlgorithmを使いましょう。あなたは、「Loopの方が分かりやすくメンテナンスしやすい」と言うかもしれませんが、それは誤りです。

何故なら、Algorithmはどのような動作を行うかは明確に分かりますが、Loopがどのような動作をするかはそれぞれのLoopのコードを読み解かないと分かりません。Loopで明確なのはループ処理を行っているという事実だけで、実際の処理内容は読み解かなければなりません。

また、Algorithmを使わずLoopを書くということは、std::memcpy()やstd::strcpy()やstd::strlen()等を使わずにLoopを書くということと同じことです。

あなたはそれでもAlgorithmを使わずにLoopを書きますか?

Notes
1. 東方算程譚 - 「難しい」ってどーゆーことなんだろう
2. Effective STL - 第43項 独自に作成したループよりアルゴリズムの呼び出しを優先して使おう
Effective STL―STLを効果的に使いこなす50の鉄則 Effective STL―STLを効果的に使いこなす50の鉄則
スコット メイヤーズ (2002/01)
ピアソンエデュケーション
この商品の詳細を見る

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

配列 array

Problem
配列をSTLコンテナのように扱いたい。

Solution
もともと配列をalgorithmに渡すことは可能ですが、begin()/end()などのメンバ関数は当然利用できません。
しかし、std::tr1::arrayを用いれば配列をSTLコンテナのように扱えます。
正確にはarrayがスタックに積まれる固定長コンテナということになります。
#include <iostream>
#include <algorithm>
#include <tr1/array>

int main()
{
  typedef std::tr1::array<int, 10> container;
  container c;
  
  for (container::size_type pos = 0; pos < c.size(); ++pos) {
    c[pos] = pos;
  }
  
  std::copy(c.begin(), c.end(),
            std::ostream_iterator<container::value_type>(std::cout, ", "));
  std::cout << std::endl;
  
  return 0;
}
実行結果はこうなります。
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

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

std::stringの大文字/小文字変換

Problem
どのようにすれば、std::stringの大文字/小文字変換を行えますか?

Solution
std::transform()とstd::toupper()/std::tolower()を用いて簡単に書けます。
std::string str("hello, world");
std::transform(str.begin(), str.end(), str.begin(), std::toupper);
以上…ちょっと待ってください!

通常は上記の書き方で問題ありませんが、これがコンパイルエラーとなる場合があります。
例えばGCC 4.1.1で<locale>や<iomanip>をインクルードしている場合、以下のようなコンパイルエラーが発生します。
g++ -c -pipe -Wall -W -Werror -g -o main.o main.cpp
main.cpp: In function ‘int main()’:
main.cpp:10: error: no matching function for call to ‘transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)’
そこで、本来のシグネチャー
int toupper(int)
int tolower(int)
を明示的に指定すればコンパイルが行えます。
std::transform(str.begin(), str.end(), str.begin(), (int (*)(int))std::toupper);

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

Exceptional C++ Style - 8 テンプレートをfriendに

Problem
Exceptional C++ Styleの訳本が出版されました。
「8 テンプレートをfriendに」では、GCCが他のコンパイラに比べて標準規格対応が劣っていましたが、最新のgccではどうでしょうか?

Solution

Exceptional C++ Styleの原著が2004年発刊と少しばかり古いので「8 テンプレートをfriendに」におけるコンパイラのバージョンが古かったりします。
そこで問題になっていたgccに関して、最新のGCC 4.1.1でテストしてみましょう。
まず例8-1から。
// 例8-1:再度。
//
namespace boost {
  template<typename T> void checked_delete(T* x) {
    // ...その他の処理...
    delete x;
  }
}

class Test {
  ~Test() {}
  friend void boost::checked_delete(Test* x);  // 元のコード。
};

int main() {
  boost::checked_delete(new Test);
}
結果は、
g++ -c -pipe -Wall -W -Werror -g -o main.o main.cpp
main.cpp:12: error: ‘void boost::checked_delete(Test*)’ should have been declared inside ‘boost’
main.cpp: In function ‘void boost::checked_delete(T*) [with T = Test]’:
main.cpp:16:   instantiated from here
main.cpp:11: error: ‘Test::~Test()’ is private
main.cpp:6: error: within this context
make: *** [main.o] エラー 1
ということでGCC 4.1.1でもコンパイルできませんでした。

次に例8-2。
// 例8-2:friend宣言の別の方法。
//
namespace boost {
  template<typename T> void checked_delete(T* x) {
    // ...その他の処理...
    delete x;
  }
}

class Test {
  ~Test() {}
  friend void boost::checked_delete<>(Test* x);  // 代替案。
  //friend void boost::checked_delete<Test>(Test* x);  // 等価。
};

int main() {
  boost::checked_delete(new Test);
}
こちらはOK。

結局、結論は「例8-2」を使おう!ということになります。

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

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

スマートポインタ

Problem
安全にポインタを扱うためにはどうすれば良いでしょうか?

Solution
スマートポインタを使いましょう。

スマートポインタとは、ポインタのように「オブジェクトを指し示す」もので、ポインタにない機能を持つ賢いポインタのことです。

ポインタは便利な機能ですが、オブジェクトの生存期間の管理がプログラマに委ねられるため、Memory leakやWild pointer(Dangling pointer)に注意する必要があります。そこでスマートポインタを用いることで、安全にポインタを使用することができます。

C++98/C++03にはstd::auto_ptrというスマートポインタが用意されていますが、C++0xにはstd::tr1::shared_ptrという参照カウント型のスマートポインタが追加されます。

GCC 4.1.1には既にtr1が実装されているので試してみました。
#include <iostream>
#include <tr1/memory>

class ValueType {
public:
  ValueType() { std::cout << "    ValueType::ValueType()" << std::endl; }
  ~ValueType() { std::cout << "    ValueType::~ValueType()" << std::endl; }
};

void func()
{
  std::cout << "  func() begin" << std::endl;
  std::tr1::shared_ptr<ValueType> ptr(new ValueType);
  std::cout << "  func() end" << std::endl;
}

int main()
{
  std::cout << "main() begin" << std::endl;
  func();
  std::cout << "main() end" << std::endl;
  return 0;
}
実行結果は以下のようになります。
main() begin
  func() begin
    ValueType::ValueType()
  func() end
    ValueType::~ValueType()
main() end

人気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