4

通常のポインターを使用してプロジェクトを作成しましたが、手動のメモリ管理にうんざりしています。

リファクタリング中に予想される問題は何ですか?

これまで、メモリを自動的に管理したい型を置き換えるのにすでに 1 時間も費やしていましX*shared_ptr<X>。その後、 に変更dynamic_castしましたdynamic_pointer_cast。まだ多くのエラーが表示されます ( と比較して、関数NULLに渡しthisます)。

質問が少し漠然としていて主観的であることは承知していますが、すでにこれを行った人の経験から恩恵を受けることができると思います.

落とし穴はありますか?

4

5 に答える 5

4

boost::shared_pointerどこでも使用するのは簡単ですが、所有権のセマンティクスに従って正しいスマート ポインターを使用する必要があります。

ほとんどの場合、std::unique_ptr所有権が複数のオブジェクト インスタンス間で共有されていない限り、デフォルトで使用することをお勧めします。

周期的な所有権の問題が発生した場合は、 で周期を分割できますboost::weak_ptr

また、shared_ptr を渡すときは、別のエンティティに所有権を本当に譲渡したい場合を除き、パフォーマンス上の理由 (アトミック インクリメントを回避する) のために、常に const 参照によってそれらを渡す必要があることに注意してください。

于 2012-05-08T22:00:15.437 に答える
3

落とし穴はありますか?

はい、マーフィーの法則により、すべてのポインターをやみくもに shared_ptr に置き換えると、それはあなたが望んでいたものではないことが判明し、あなたが導入したバグを探すのに次の 6 か月を費やすことになります。

リファクタリング中に予想される問題は何ですか?

非効率的なメモリ管理、未使用のリソースが必要以上に長く保存される、メモリ リーク (循環参照)、無効な参照カウント (複数の異なる shared_pointers に割り当てられた同じポインタ)。

すべてをやみくもに shared_ptr に置き換えないでください。プログラムの構造を注意深く調査し、shread_ptr が必要であり、それが必要なものを正確に表していることを確認してください。

また、簡単な分岐 (git または mercurial) をサポートするバージョン管理を使用していることを確認してください。これにより、何かを壊したときに、以前の状態に戻すか、「git bisect」のようなものを実行して問題を特定できます。

明らかに X* を shared_ptr に置き換える必要があります

違う。それは文脈に依存します。配列の中央を指すポインターがある場合 (ピクセル データ操作など)、それを shared_ptr に置き換えることはできません (また、その必要はありません)。オブジェクトの自動割り当て解除を確実にする必要がある場合にのみ、shared_ptr を使用する必要があります。オブジェクトの自動割り当て解除は、必ずしも必要なものではありません。

于 2012-05-08T23:32:59.000 に答える
2

ブーストに固執したい場合は、boost::shared_ptr または boost::scoped_ptr が必要かどうかを検討する必要があります。shared_ptr はクラス間で共有されるリソースですが、scoped_ptr は (少なくともいくつかの場所では) あなたが望むもののように聞こえます。scoped_ptr は、スコープ外になるとメモリを自動的に削除します。

関数に shared_ptr を渡すときは注意してください。shared_ptr の一般的な規則は、コピーが作成されるように値渡しすることです。参照渡しの場合、ポインタの参照カウントはインクリメントされません。この場合、保存したかったメモリの一部を削除してしまう可能性があります。

ただし、参照によって shared_ptr を渡したい場合があります。つまり、メモリを別の関数内に割り当てたい場合です。この場合、呼び出し元が、呼び出している関数の存続期間中、ポインターを保持していることを確認してください。

void allocPtr( boost::shared_ptr< int >& ptrByRef )
{
    ptrByRef.reset( new int );
    *ptrByRef = 3;
}

int main()
{
    boost::shared_ptr< int >& myPointer;
    // I want a function to alloc the memory for this pointer.

    allocPtr( myPointer ); // I must be careful that I still hold the pointer
                           // when the function terminates

    std::cout << *ptrByRef << std::endl;
}
于 2012-05-09T04:27:28.690 に答える
2

関連する手順/問題をリストしています。彼らは私のために働いたが、私は彼らが100%正しいとは保証できない

0) 循環共有ポインタが存在する可能性があるかどうかを確認します。もしそうなら、これはメモリリークにつながる可能性がありますか? 私の場合、幸運なことに、サイクルを壊す必要はありません。なぜなら、サイクルがあれば、サイクル内のオブジェクトは有用であり、破壊されるべきではないからです。ウィーク ポインターを使用してサイクルを中断する

X*1) 「ほとんど」をに置き換える必要がありますshared_ptr<X>。shared_ptr は (のみ?) X のすべての動的割り当ての直後に作成されます。それ以外の場合は常に、コピーで構築されるか、空のポインターで構築されます (シグナル NULL へ)。安全のために (ただし、少し非効率的です)、これらの shared_ptrs は参照によってのみ渡します。とにかく、そもそも参照によってポインタを渡したことがない可能性があります => 追加の変更は必要ありません

2)dynamic_cast<X*>(y)いくつかの場所で使用した可能性があります。それを dynamic_pointer_cast<X>(y)

3) 渡した場所NULL(たとえば、計算が失敗したことを通知するため) には、空の共有ポインターを渡します。

4) 関連するタイプのすべての削除ステートメントを削除します

5) 基本クラス B を から継承させenable_shared_from_this<B>ます。次に、あなたが通過したところはどこでもthis、通過しshared_from_this()ます。関数が派生型を想定している場合は、静的キャストが必要になる場合があります。を呼び出すときは、すでに を所有してshared_from_this()いる必要があることに注意してください。特に、クラスのコンストラクタで呼び出さないでくださいshared_ptrthisshared_from_this()

このプロセスを半自動化して、意味的に同等のコードを取得できると確信していますが、必ずしも非常に効率的なコードではありません。プログラマーはおそらく、循環参照 (もしあれば) について推論する必要があるだけです。

これらのステップの多くで、正規表現を頻繁に使用しました。3~4時間ほどかかりました。コードはコンパイルされ、これまでのところ正しく実行されています。

于 2012-05-09T23:24:22.370 に答える
0

スマート ポインターに自動的に変換しようとするツールがあります。私はそれを試したことがない。以下は、次の論文の要約からの引用です

静的にチェックするのが難しい安全性プロパティを適用するために、Ironclad C++ はテンプレート化された「スマート ポインター」クラスを介して動的チェックを適用します。半自動リファクタリング ツールを使用して、約 5 万行のコードを Ironclad C++ に移植しました。

于 2014-10-06T03:51:41.903 に答える