19

このコードを検討してください:

#include <memory>
#include <iostream>


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

    ~SomeClass() {
        std::cout << "~SomeClass()" << std::endl;
    }

    void* operator new(std::size_t size) {
        std::cout << "Custom new" << std::endl;
        return ::operator new(size);
    }

    void operator delete(void* ptr, std::size_t size) {
        std::cout << "Custom delete" << std::endl;
        ::operator delete(ptr);
    }
};



int main() {
    std::shared_ptr<SomeClass> ptr1(new SomeClass);
    std::cout << std::endl << "Another one..." << std::endl << std::endl;
    std::shared_ptr<SomeClass> ptr2(std::make_shared<SomeClass>());
    std::cout << std::endl << "Done!" << std::endl << std::endl;
}

その出力は次のとおりです。

Custom new
SomeClass()

Another one...

SomeClass()

Done!

~SomeClass()
~SomeClass()
Custom delete

明らかにstd::make_shared()、オペレーターを呼び出していませんnew。カスタム アロケーターを使用しています。これは の標準的な動作std::make_shared()ですか?

4

2 に答える 2

18

はい、これは標準的な動作です。標準から (§20.7.2.2.6 shared_ptr の作成):

効果: 型 T のオブジェクトに適したメモリを割り当て、placement new 式を介してそのメモリ内にオブジェクトを構築します。::new (pv) T(std::forward<Args>(args)...).

これによりmake_shared、効率上の理由から、共有ポインター自体 (「制御ブロック」) のオブジェクトとデータ構造の両方にストレージを 1 回の割り当てで割り当てることができます。

std::allocate_sharedそのストレージ割り当てを制御したい場合に使用できます。

于 2012-12-29T09:42:50.877 に答える
5

マットの正解を拡張するには、通常、参照カウントと初期化されていないバイトのバッファーをmake_shared含むオブジェクトを割り当てることによって実装されます。shared_ptr

template<typename T>
  struct shared_count_inplace
  {
    long m_count;
    long weak_count;
    typename std::aligned_storage<sizeof(T)>::type m_storage;
    // ...
  };

これはあなたのタイプではなくヒープに割り当てられるタイプなので、あなたのタイプnewは呼び出されません。new次に、 location での配置を使用してタイプが構築されます(void*)&m_storage

于 2012-12-30T19:07:05.463 に答える