[解決済み] C++でstd::functionと関数ポインタのどちらを使うべきですか?
質問
C++でコールバック関数を実装する場合、Cスタイルの関数ポインタを使用した方が良いですか?
void (*callbackFunc)(int);
それともstd::functionを利用した方がいいのでしょうか。
std::function< void(int) > callbackFunc;
解決方法は?
要するに
std::function
特に理由がない限り
関数ポインタは、以下のような欠点があります。
をキャプチャすることができません。
あるコンテクストがあります。例えば、ラムダ関数をコールバックとして渡して、コンテキスト変数を取得することはできません(ただし、何も取得しない場合は動作します)。オブジェクトのメンバ変数 (つまり非静的変数) を呼び出すことも、オブジェクト (
this
-ポインタ)をキャプチャする必要があります。
(1)
std::function
(C++11以降)は、主に
ストア
を関数として使用することができます(渡すだけでは格納する必要はありません)。したがって、例えばコールバックをメンバ変数に格納したい場合は、おそらくこれが最良の選択となる。しかし、コールバックを保存しない場合、これは良い最初の選択肢となります。これは非常に普遍的なものです。一貫性のある読みやすいコードにこだわりがあり、すべての選択について考えたくない(つまり、シンプルでありたい)場合は
std::function
を渡すすべての関数に使用します。
3つ目の選択肢を考えてみましょう。もし、小さな関数を実装して、その関数が提供するコールバック関数を通じて何かを報告するのであれば、その関数の中に
テンプレートパラメータ
にすることができます。
任意の呼び出し可能なオブジェクト
すなわち、関数ポインタ、ファンクタ、ラムダ、
std::function
, ... この欠点は、(外側の)関数がテンプレートになるため、ヘッダで実装する必要があることです。一方、コールバックの呼び出しはインライン化できるという利点があります。なぜなら、外側の関数のクライアントコードは、コールバックの呼び出しを正確に理解し、型情報を利用することができるからです。
テンプレート・パラメータを使用したバージョンの例(write
&
の代わりに
&&
はC++11以前のバージョン)。
template <typename CallbackFunction>
void myFunction(..., CallbackFunction && callback) {
...
callback(...);
...
}
以下の表でお分かりのように、どれも一長一短がありますね。
<サブ
(1) この制限を克服するための回避策があります。例えば、追加データを(外側の)関数のさらなるパラメータとして渡すことができます。
myFunction(..., callback, data)
が呼び出されます。
callback(data)
. これは、C++でも可能ですが(ちなみにWIN32 APIで多用されています)、C++ではより良いオプションがあるので避けるべきです。
<サブ (2) クラステンプレート、つまり関数を格納するクラスがテンプレートであるという話でなければ。しかし、それではクライアント側で関数の型がコールバックを格納するオブジェクトの型を決定することになり、実際のユースケースではほとんど選択肢に入りません。
<サブ
(3) C++11以前のバージョンでは
boost::function
関連
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み] callとapplyの違いは何ですか?
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] static_cast, dynamic_cast, const_cast, reinterpret_cast はいつ使うべきですか?
-
[解決済み] コピーアンドスワップ慣用句とは?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] コールバック内で正しい `this` にアクセスする方法
-
[解決済み】なぜC++プログラマは'new'の使用を最小限に抑えなければならないのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】getline()が何らかの入力の後に使用されると動作しない 【重複あり
-
[解決済み】文字列関数で'char const*'のインスタンスを投げた後に呼び出されるterminate [閉店].
-
[解決済み】浮動小数点例外エラーが発生する: 8
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】 while(cin) と while(cin >> num) の違いは何ですか?)
-
[解決済み】Enterキーを押して続行する
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++
-
[解決済み】キャプチャしたラムダを関数ポインタとして渡す