6

boost :: make_sharedを初めて使用して、共有ポインターが指すオブジェクトを作成しています。主な理由は、コードが遅すぎて、単一の割り当てがパフォーマンスの向上に本当に役立ったためです。

いくつかのメモリリークを「難しい手動の方法」で修正した後、アプリケーションの特定のポイントでまだ生きているオブジェクトを数えるためだけに、関連するすべてのクラスの新しい演算子をオーバーライドすることで、単純なメモリリーク検出器を実装することにしました。私はこれを数回実装しましたが、コードがオブジェクトを検出しなくなったことに驚きました。

make_sharedのブーストWebサイトのドキュメントから次の理由により、「通常の」演算子newではなく「placementnew」をオーバーライドするだけでよいと考えました。

"効果:タイプTのオブジェクトに適したメモリを割り当て、配置new式new(pv)T()またはnew(pv)T(std :: forward(args)...)を介してその中にオブジェクトを構築します。allocate_sharedのコピーを使用してメモリを割り当てます。例外がスローされた場合、効果はありません。」

ただし、新しい配置も呼び出されていません。動作を再現するための小さなテストプログラムを作成しました。

#include <iostream>
using namespace std;
#include "boost/shared_ptr.hpp"
#include "boost/make_shared.hpp"

class Test
{
public:
    Test() { cout << "Test::Test()" << endl; }

    void* operator new (std::size_t size) throw (std::bad_alloc) {
        cout << "Test new" << endl;
        return malloc(size);
    }

    void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw() {
        cout << "Test non-throwing new" << endl;
        return malloc(size);
    }

    void* operator new (std::size_t size, void* ptr) throw() {
        cout << "Test non-throwing placement new" << endl;
        return malloc(size);
    }
};

void* operator new (std::size_t size) throw (std::bad_alloc) {
    cout << "Global new" << endl;
    return malloc(size);
}

int main() {
    cout << "..." << endl;
    boost::shared_ptr<Test> t1(boost::make_shared<Test>());
    cout << "..." << endl;
    boost::shared_ptr<Test> t2(new Test());
    cout << "..." << endl;

    return 0;
}

これにより、次の出力がレンダリングされます。

...
Global new
Test::Test()
...
Test new
Test::Test()
Global new
...

出力の3行目に「新しい非スロー配置をテストする」と期待していました。行動はどうあるべきだと思いますか?make_sharedのドキュメントによると、配置を私のテストクラスの新しい演算子と呼ぶことに同意しますか?それとも私はそれを誤解しましたか?

もちろん、ブーストの実装をローカルにコピーして、配置の新しい演算子に呼び出しを追加することもできます。しかし、それは適切でしょうか、それとも新しい配置構文の意図されたセマンティクスに違反するのでしょうか?

あなたの時間とあなたの助けを前もって感謝します。

4

3 に答える 3

8

のソースとして見ると、クラスによって提供される新しい演算子の代わりに、make_sharedグローバル配置演算子を使用します。new

::new( pv ) T();

残念ながら(少なくともOS Xでは)標準によると)、独自のグローバル配置の新しい演算子を定義することはできません。それallocate_sharedはあなたが探しているものの線にもっと沿っているようです。

編集

make_shared別の方法として、グローバルな配置ではなく、クラスの配置を新しいものとして使用するバージョンを実際に作成することもできます。たった10行のコードで、元のコードのライセンスを尊重する限り問題ありません。

于 2012-03-12T22:16:02.727 に答える
4

新しい配置を置き換えることはできません(§18.4。1.3、たとえばこの質問を参照)ので、与えられた出力は問題ないようです。

Boostヘッダーを変更する代わりに、Valgrindなどの外部ツールを調べることもできます。

于 2012-03-12T22:14:59.413 に答える
3

特定のタイプに実装されたものは、タイプの要素が で動的に割り当てられるoperator newでのみ使用されます。現在、タイプのオブジェクトを動的に割り当てるのではなく、共有カウント(カウンター、デリータ、およびいくつかの余分なビットとピースを含む) とオブジェクトに十分な情報を保持するバッファーを割り当てます。newTest *p = new Test;make_shared

次に、placement-newを使用してオブジェクトのコンストラクターを呼び出します。この場合の配置 newはメモリの割り当てではないことに注意してください。すでに割り当てられているメモリのブロックでコンストラクターを呼び出すのは、C++ の面白い構文にすぎません。これは実際には混乱の元になる可能性がありnewます。expression、your operator newplacement-newは 3 つの異なる概念であり、たまたま名前を共有しているからです。

于 2012-03-12T22:26:37.777 に答える