読者です 読者をやめる 読者になる 読者になる

ゆとりーなの日記

日記的な事を書いて行くと思はれる

パイソンとか使えよという主張

っていう主張が友人からでました。彼曰く「C++は速度出すために使うようなもんだし、shared_ptrとかpimplとか使う位なら最初からPythonとか使えばいい」らしいです。
まぁshared_ptrでネックになるのは多分マルチスレッド対応の参照カウンタの増減の部分、pimplは実装クラスの生成とポインタ経由のメンバアクセスがネックになると思うのですが、まぁVC++2010のReleaseでどれくらい差が出るかを試したわけです。

shared_ptr

#include <iostream>
#include <memory>
#include <boost/timer.hpp>

int main() {
  boost::timer t;
  const int * const p = new int(0);
  for (int i = 0; i < 100000000; ++i) {
    const int * const tp = p;
  }
  std::cout << t.elapsed() << std::endl;
  delete p;
  t.restart();
  const std::shared_ptr<const int> sp = std::make_shared<int>(0);
  for (int i = 0; i < 100000000; ++i) {
    const std::shared_ptr<const int> tsp = sp;
  }
  std::cout << t.elapsed() << std::endl;
  return 0;
}
出力
0
2.916

pimpl

#include <iostream>
#include <memory>
#include <boost/timer.hpp>

class hoge {
 public:
  hoge() : i_(0) {}
  int i() const {return i_;}
 private:
  const int i_;
};

class hageimpl {
 public:
  hageimpl() : i_(0) {}
  int i() const {return i_;}
 private:
  const int i_;
};

class hage {
 public:
  hage() : impl_(new hageimpl()) {}
  int i() const {return impl_->i();}
 private:
  const std::unique_ptr<hageimpl> impl_;
};

int main() {
  boost::timer t;
  for (int i = 0; i < 100000000; ++i) {
    hoge h;
    const int j = h.i();
  }
  std::cout << t.elapsed() << std::endl;
  t.restart();
  for (int i = 0; i < 100000000; ++i) {
    hage h;
    const int j = h.i();
  }
  std::cout << t.elapsed() << std::endl;
  return 0;
}
出力
0
13.372

総括

結構差が出ますね。pimplの方は毎回newする分やっぱり遅くなるみたいです。shared_ptrの方はマルチスレッドじゃないよと教えてあげれば参照カウンタの増減に保護が入らなくなるというオプションがBoostにはあったと記憶しているのですが、0x標準にそれが入ってるのかは知りません。まぁいずれにしてもC++でテクニックを使うと生で使う黒魔術に比べ遅くなるのは事実ですが、だからといってそれが即Pythonなりインタプリタを使うべしとなるのかどうかは疑問です。
追記:
コンパイラの本気により生ポインタ、pimplなしの方は最適化されてしまっているため実際は大して比較が出来ていないという現実があります。
というわけでちょっと修正してみました。

shared_ptr

#include <iostream>
#include <memory>
#include <boost/timer.hpp>

int main() {
  int i;
  int val = 0;
  boost::timer t;
  const int * const p = &i;
  for (i = 0; i < 100000000; ++i) {
    const int * const tp = p;
    val += *tp;
  }
  std::cout << t.elapsed() << std::endl;
  t.restart();
  const std::shared_ptr<const int> sp(&i, [](const int * const) {});
  for (i = 0; i < 100000000; ++i) {
    const std::shared_ptr<const int> tsp = sp;
    val += *tsp;
  }
  std::cout << t.elapsed() << std::endl;
  std::cout << val << std::endl;
  return 0;
}
出力
0.093
4.028
1774919424

pimpl

#include <iostream>
#include <memory>
#include <boost/timer.hpp>

class hoge {
 public:
  hoge(const int i) : i_(i) {}
  int i() const {return i_;}
 private:
  const int i_;
};

class hageimpl {
 public:
  hageimpl(const int i) : i_(i) {}
  int i() const {return i_;}
 private:
  const int i_;
};

class hage {
 public:
  hage(const int i) : impl_(new hageimpl(i)) {}
  int i() const {return impl_->i();}
 private:
  const std::unique_ptr<hageimpl> impl_;
};

int main() {
  int val;
  boost::timer t;
  for (int i = 0; i < 100000000; ++i) {
    hoge h(i % 2);
    val += h.i();
  }
  std::cout << t.elapsed() << std::endl;
  t.restart();
  for (int i = 0; i < 100000000; ++i) {
    hage h(i % 2);
    val += h.i();
  }
  std::cout << t.elapsed() << std::endl;
  std::cout << val << std::endl;
  return 0;
}
出力
0.144
13.364
100000000