コンテンツにスキップ

最終更新:2026-10-12

C++ 初期化と代入

C++ iv

int* p = nullptr;
std::shared_ptr<int> s(p); // 计数器1
std::shared_ptr<int> s2(s); // 计数器2
assert(s.use_count() == 2); 

このコードはいくつかの疑問を引き起こします:

  • なぜnullptrの生ポインタから構築されたスマートポインタの参照カウンタは0ではないのか?
  • delete nullptrは安全なのか?

1.空のshared_ptrの意味

shared_ptrのソースコードを直接見てみましょう。いわゆる**空**とは次を指します:

  • デフォルト構築されたshared_ptr
  • nullptr_tから構築されたshared_ptr

この2つの場合が空であり、生ポインタから構築されたshared_ptrは、それが空であろうとなかろうと、そのポインタの所有権を占有します。

それぞれ下の3つのコンストラクタに対応します。

private:
    element_type*      __ptr_;
    __shared_weak_count* __cntrl_;

public:
    _LIBCPP_HIDE_FROM_ABI
    _LIBCPP_CONSTEXPR shared_ptr() _NOEXCEPT
        : __ptr_(nullptr),
          __cntrl_(nullptr)
    { }

    _LIBCPP_HIDE_FROM_ABI
    _LIBCPP_CONSTEXPR shared_ptr(nullptr_t) _NOEXCEPT
        : __ptr_(nullptr),
          __cntrl_(nullptr)
    { }
    shared_ptr(_Yp* __p, _Dp __d)
        : __ptr_(__p)
    {}

上のように生ポインタがnullptrの場合、delete nullptrを実行すると何が起こるでしょうか?2回削除すると何が起こるでしょうか?

2.delete nullptr

次のコードがあるとします。実行するとクラッシュするでしょうか?それとも正常に動くでしょうか?

#include <iostream>

int main() {
    int *p = nullptr;
    delete p;
    std::cout << "delete once" << std::endl;
    delete p;
    std::cout << "delete twice" << std::endl;

}

答えは、正常に出力されます。

具体的な理由はcppreferenceを参照してください:

If expression evaluates to a null pointer value, no destructors are called, and the deallocation function may or may not be called (it's unspecified), but the default deallocation functions are guaranteed to do nothing when passed a null pointer.

https://en.cppreference.com/w/cpp/language/delete

式の評価結果がヌルポインタ値である場合、デストラクタは呼び出されず、解放関数は呼ばれる場合と呼ばれない場合があります(未指定)。ただし、デフォルトの解放関数は、ヌルポインタを渡されたとき何もしないことが保証されています。

読書のヒント

本記事では C++ における**初期化**(initialization)と**代入**(assignment)の違いについて論じます。クラス初期化リストを参照してください。

関連トピック

コメント