最終更新: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.
式の評価結果がヌルポインタ値である場合、デストラクタは呼び出されず、解放関数は呼ばれる場合と呼ばれない場合があります(未指定)。ただし、デフォルトの解放関数は、ヌルポインタを渡されたとき何もしないことが保証されています。
読書のヒント
本記事では C++ における**初期化**(initialization)と**代入**(assignment)の違いについて論じます。クラス初期化リストを参照してください。
関連トピック¶
- C++ 純粋仮想関数と抽象クラス | C++那些事
- C++ assert アサーション | C++那些事
- C++ ビットフィールド | C++那些事
- C 言語による C++ 多態の実現 | C++那些事
- C++ const 定数と修飾 | C++那些事
- C++ const ファミリー | C++那些事
- C++ 間接参照演算子 * | C++那些事
- C++ 複数戻り値の書き方 | C++那些事
- C++ mutable キーワード | C++那些事
- C++ restrict とコンパイル最適化 | C++那些事