1

無理かもしれませんが、質問させていただきます...

変数自体のクラスを変更せずに自動変数が削除されたかどうかを追跡する方法はありますか? たとえば、次のコードを検討してください。

const char* pStringBuffer;
{
    std::string sString( "foo" );
    pStringBuffer = sString.c_str();
}

明らかに、ブロックの後、pStringBuffer はダングリング ポインターであり、有効である場合と有効でない場合があります。私が望むのは、pStringBuffer (const char* のキャスト演算子を含む) を含むラッパー クラスを持つ方法ですが、参照している変数がまだ有効であることを主張します。参照される変数の型を変更することで、確かにそれを行うことができます (たとえば、shared_ptr/weak_ptr をブーストする) が、参照される型に制限を課すことなく実行できるようにしたいと考えています。

いくつかの考え:

  • おそらく、代入構文を変更して、参照された変数を含める必要があります (これで問題ありません)。
  • ラッパー クラスが参照されたクラスよりも「後で」割り当てられたかどうかを検出するためにスタック ポインターを調べることができるかもしれませんが、これはハッキーで標準的ではないようです (C++ はスタックの動作を定義していません)。しかし、それはうまくいくかもしれません。

考え/素晴らしい解決策はありますか?

4

4 に答える 4

1

一般に、ポインターはあまりにも「未加工」であるため、C++ 内からは単純に不可能です。また、文字列を変更すると、 c_str ポインターが変更される可能性があるため、参照されたクラスよりも後に割り当てられたかどうかを確認することはできません。

この特定のケースでは、文字列が c_str に対して同じ値を返しているかどうかを確認できます。そうである場合、おそらくまだ有効であり、そうでない場合は、無効なポインターがあります。

デバッグ ツールとして、valgrind のような高度なメモリ トラッキング システムを使用することをお勧めします (Linux でのみ利用可能です。Windows 用の同様のプログラムもありますが、すべて費用がかかると思います。Linux をインストールした唯一の理由はこのプログラムです)。私のMacで)。プログラムの実行が大幅に遅くなるという代償を払って、valgrind は、無効なポインターから読み取ったことがあるかどうかを検出します。完璧ではありませんが、多くのバグ、特にこのタイプのバグを検出できることがわかりました。

于 2008-10-16T23:10:21.840 に答える
0

役立つと思われる手法の 1 つは、new/delete演算子を独自の実装に置き換えて、使用されている ( によって割り当てられている) メモリ ページをoperator new解放 ( によって割り当て解除) されたときにアクセス不可としてマークすることoperator deleteです。ただし、メモリページが再利用されないようにする必要があるため、メモリの枯渇による実行時間の長さに関する制限があります。

上記の例のように、割り当てが解除されたメモリ ページにアプリケーションがアクセスすると、OS は試行されたアクセスをトラップし、エラーを発生させます。アプリケーションはすぐに停止されるため、正確に追跡するわけではありませんが、フィードバックを提供します:-)

この手法は狭いシナリオに適用でき、すべての種類のメモリの乱用を検出できるわけではありませんが、役立つ場合があります。それが役立つことを願っています。

于 2008-10-16T23:08:08.287 に答える
0

あなたが言及した単純なケースで機能するラッパークラスを作成できます。多分このようなもの:

X<const char*> pStringBuffer;
{
    std::string sString( "foo" );
    Trick trick(pStringBuffer).set(sString.c_str());
} // trick goes out of scope; its destructor marks pStringBuffer as invalid

しかし、より複雑なケースでは役に立ちません:

X<const char*> pStringBuffer;
{
    std::string sString( "foo" );
    {
        Trick trick(pStringBuffer).set(sString.c_str());
    } // trick goes out of scope; its destructor marks pStringBuffer as invalid
}

ここでは、無効化が早すぎます。

ほとんどの場合、可能な限り安全なコード (スマート ポインターを参照) を作成する必要がありますが、より安全ではありません (パフォーマンス、低レベル インターフェイスを参照)。

于 2008-10-16T23:57:28.687 に答える
0

「pStringBuffer」が sString が範囲外になった後に存在する例の唯一の部分であることを考えると、これを反映する変更または代替が必要です。単純なメカニズムの 1 つは、スコープが sString に一致する一種のスコープ ガードであり、破棄されたときに pStringBuffer に影響を与えます。たとえば、pStringBuffer を NULL に設定できます。

「変数」のクラスを変更せずにこれを行うには、非常に多くの方法でしか実行できません。

  • sString と同じスコープに個別の変数を導入します (冗長性を減らすために、マクロを使用して 2 つのものを一緒に生成することを検討してください)。よくない。

  • テンプレート ala X sString でラップします。これが「変数の型を変更する」かどうかは議論の余地があります...別の見方は、sString が同じ変数のラッパーになるということです。また、テンプレート化されたコンストラクターがラップされたコンストラクターに引数をいくつかの有限 N 個の引数まで渡すようにすることが最善であるという点でも問題があります。

これらは、開発者が使用することを覚えていることに依存しているため、どちらもあまり役に立ちません。

より良い方法は "const char* pStringBuffer" を単に "std::string some_meaningful_name" にして、必要に応じて割り当てることです。参照カウントを考えると、99.99% の確率でそれほど高価ではありません。

于 2008-10-17T10:06:20.860 に答える