19

C/C++ プログラムが混在しています。C を対象とする flex/bison パーサーが含まれていますが、残りは C++ です。

C であるため、生成されたパーサーとスキャナーはmalloc、 、reallocおよび でメモリを管理しますfree。それらは、フックを公開して、これらの関数の独自の実装を送信できるようにするのに十分です。ご想像のとおり、(C++) プログラムの残りの部分ではnewdelete、 などを使用する必要があります。

少し調べてみると、関連する規格がそのような混合が機能することを保証していないことが示されているようです。特に、C の「ヒープ」は必ずしも C++ の「空き領域」とは限りません。2 つのスキームは互いに踏みにじることができるようです。

これに加えて、いつか (近いうちに) このプログラムは、C と C++ の両方で使用されるtcmallocなどのカスタマイズされたヒープ実装を統合する必要があるでしょう。

ここで「正しい」ことは何ですか?

tcmalloc (C プログラムとのリンク方法を説明しています) を統合したいという願望を考えると、クロスタイプ、クロススレッド、クロスオーバーロード/フックなどを C++ メモリ管理に見つけたいと思っています。これにより、すべての C++ の割り当て/解放呼び出しを C の同等のものに戻すことができます (これが tcmalloc に到達します)。

そのような銀河全体のグローバルな C++ フックは存在しますか? ios_base::sync_with_stdioデフォルトで iostream と stdio を密かに結合する方法と同様に、すでに私が望むことを行っているのでしょうか?

stdio と iostream の話にも、パーサー ジェネレーターの切り替えにも、C++ flex/bison スケルトンの使用にも興味がありません (これらは独立した頭痛の種です)。

EDIT : あなたの回答をサポートする C++ 標準のセクションの名前を含めてください。

4

3 に答える 3

29

標準では、2 つの割り当てバリアントを混在させても機能すること保証されています。許可されていないfreeのはnew、.

特定のメモリ ブロックに対して正しい割り当て解除関数を呼び出すことを覚えていれば、問題ありません。あなたがルールに従えば、彼らお互いを踏みにじることはありませんし、もしあなたがルールに従わなければ、技術的には、彼らではなくあなたが踏みにじっていることになります :-)


C++11 標準の制御部分は20.6.13 C library、言い換えると次のように述べられています。

  • 関数callocmallocfreeおよびreallocは、C 標準に基づいて提供されます。
  • ::operator new()関数はまたはを使用しません::operator delete()
  • これにより、継承された C のものが、通常の C++ メモリ割り当てとは異なるメモリ アリーナを使用できるようになります。

その 2 番目の箇条書きは、あなたが最終的に提案していることに照らして興味深いものでありtcmalloc、C の遺産関数を置き換え、C++ にもそれを使用させるために立ち寄っています。

malloc()標準には、 let callを使用しない理由を説明する脚注があり::operator new()ます。

その意図は、std::malloc() または std::calloc() を呼び出すことによって演算子 new() を実装できるようにすることです。つまり、循環依存を避けたいということです。

ただし、を呼び出すことはできます が、標準で実際に必要かどうかはわかりません。したがって、念のため、CとC++の両方の領域に注入することをお勧めします。operator new()malloc()tcmalloc

C でそれを行う方法を既に知っていることを示しました。C++ の場合operator new()/delete()、コード内でグローバル関数のセット全体を提供するだけで実行でき、内部で呼び出すように適切に記述されますtcmalloc。C++ 標準は次のように述べてい3.7.4 Dynamic storage durationます。

ライブラリは、グローバル割り当ておよび割り当て解除関数のデフォルト定義を提供します。一部のグローバル割り当ておよび割り当て解除関数は置き換え可能です。

C++ プログラムは、置換可能な割り当てまたは割り当て解除関数の定義を最大 1 つ提供する必要があります。このような関数定義は、ライブラリで提供されるデフォルト バージョンを置き換えます。

次の割り当て関数と割り当て解除関数は、プログラムの各翻訳単位のグローバル スコープで暗黙的に宣言されます。

  • void* operator new(std::size_t);
  • void* operator new[](std::size_t);
  • void operator delete(void*);
  • void operator delete[](void*);
于 2012-12-02T22:00:35.387 に答える
2

Ok。標準の古い作業ドラフトを掘り起こしました(2011年2月28日改訂3242)。関連するセクションはとであるよう3.7.4 Dynamic storage durationです18.6.1 Storage allocation and deallocation

要するに、私が欲しかった汎銀河フックは、グローバルなnew演算子とdelete演算子そのもののようです。いくつかのセマンティクスを尊重する場合(3.7.4.1および3.7.4.2:基本的にnew_handler必要に応じて委任する)、置き換えることができます

void* operator new(std::size_t);
void* operator new[](std::size_t);
void operator delete(void*);
void operator delete[](void*);

C++プログラム全体のデフォルトのメモリ管理を停止します。@paxdiabloが正しいことを証明するセクションはまだ見つかりませんが、今のところはそれを使用して実行します。

于 2012-12-02T22:54:26.217 に答える