web-dev-qa-db-ja.com

C ++の空とnullのstd :: shared_ptrの違いは何ですか?

cplusplus.com shared_ptr page は、emptystd::shared_ptrnullshared_ptrcppreference.com page は明確に区別を呼び出しませんが、std::shared_ptr動作の説明で「空」とnullptrとの比較の両方を使用します。

空のshared_ptrとnullの違いはありますか?そのような混合動作のポインターの使用例はありますか?空でないnull shared_ptrは理にかなっていますか?通常の使用法(つまり、明示的に構築しなかった場合)で、空であるがnullではないshared_ptrになる場合がありますか?

また、C++ 11バージョンの代わりにBoostバージョンを使用している場合、これらの回答のいずれかが変わりますか?

75
R.M.

shared_ptrの動作の奇妙なコーナーです。これには、owns何かとpoints to何か他のものを作成するshared_ptrを作成できるコンストラクターがあります。

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, T *ptr );

このコンストラクタを使用して構築されたshared_ptr所有権を共有rが、ポイントptrが指すもの(つまり、get()またはoperator->()ptr)を返します。これは、ptrが所有するオブジェクトのサブオブジェクト(データメンバーなど)をrが指す場合に便利です。

リンクしたページは、何も所有していないshared_ptrを呼び出しますempty、および何も指定していないshared_ptr(つまり、そのget() == nullptrnullを呼び出します。 (はこの意味で標準で使用されます; nullはそうではありません。)null-but-not-empty shared_ptrを構築できますが、そうではありません非常に便利。空ではないがnullではないshared_ptrは本質的に非所有ポインターであり、これを使用して スタックに割り当てられた何かへのポインターをshared_ptrを予期する関数に渡す (ただし、最初にAPI内にshared_ptrを入れた人は誰でもパンチすることをお勧めします)。

boost::shared_ptrこのコンストラクターを持っていますエイリアスコンストラクターと呼びます。

77
T.C.

空とnullのshared_ptrに違いはありますか?

空のshared_ptrには制御ブロックがなく、その使用カウントは0と見なされます。空のshared_ptrのコピーは別の空のshared_ptrです。どちらも別個のshared_ptrであり、共通の制御ブロックを持たないため、共通の制御ブロックを共有しません。空のshared_ptrは、デフォルトのコンストラクターまたはnullptrをとるコンストラクターで構築できます。

空でないnull shared_ptrには、他のshared_ptrsと共有できる制御ブロックがあります。空でないヌルのコピーshared_ptrは、元のshared_ptrと同じ制御ブロックを共有するshared_ptrであるため、使用回数は0ではありません。shared_ptrのすべてのコピーが同じnullptrを共有すること。空でないnull shared_ptrは、オブジェクトの型のnullptrではないnullポインタで構築できます

以下に例を示します。

#include <iostream>
#include <memory>

int main()
{
    std::cout << "std::shared_ptr<int> ptr1:" << std::endl;
    {
        std::shared_ptr<int> ptr1;
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(nullptr):" << std::endl;
    {
        std::shared_ptr<int> ptr1(nullptr);
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl;
    {
        std::shared_ptr<int> ptr1(static_cast<int*>(nullptr));
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    return 0;
}

以下を出力します:

std::shared_ptr<int> ptr1:
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(nullptr):
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))
    use count before copying ptr: 1
    use count  after copying ptr: 2
    ptr1 is null

http://coliru.stacked-crooked.com/a/54f59730905ed2ff

6
anton_rh