Try   HackMD

unique_ptr のconstとは?

unique_ptr にconst修飾子がついているケースがChromiumでも散見される。

const std::unique_ptr<viz::CompositorRenderPass>& render_pass = frame.render_pass_list.back();

constがつくとどういう挙動になるのかを確認する。

そもそもconstとは

constは変数前につけることでその変数の値を不変にする修飾子。
例えばconst int val = 0と変数valを宣言すると違う値を再代入することはできない。
val = 1とかいたらコンパイルエラーになる。

constはポインタにつけると挙動がややこしくなる。
ポインタ変数は、指すアドレスそのものを変更できるかと、指す先の値を変更できるかの2タイプ存在する。
それはconstをつける位置によって変わる。

// 値の場合const intとint constは同じ const int val1 = 0; // val1 = 1; <- コンパイルエラー int const val1 = 0; // val2 = 1; <- コンパイルエラー // ポインタの場合constとint*のどちらを先に書くかで変わる int val = 0; const int* ptr1 = &val; ptr1 = nullptr; // <- OK // *ptr1 = 1; <- コンパイルエラー int* const ptr2 = &val; // ptr2 = nullptr; <- コンパイルエラー *ptr2 = 1; // <- OK // どちらもつけることもできる。その場合どちらも制約がつく const int* const ptr3 = &val; // ptr3 = nullptr; <- コンパイルエラー // *ptr3 = 1; <- コンパイルエラー

std::unique_ptrの場合

ではstd::unique_ptrとconstの関係を見る。
まず先頭にconstをつけてみる。

const std::unique_ptr<int> uptr1 = std::make_unique<int>(0); // uptr1 = nullptr; <- コンパイルエラー *uptr1 = 1; // <- OK

生ポインタにおけるint* const ptr2と同じ挙動をした。
ではconst int*にあたる書き方はどうすればいいかというと以下。

std::unique_ptr<const int> uptr2 = std::make_unique<const int>(0); uptr2 = nullptr; // OK // *uptr2 = 1; <- コンパイルエラー

格納する値をconstにすればよい。

生ポインタと同様に、どちらも不変にすることもできる。

const std::unique_ptr<const int> uptr3 = std:make_unique<const int>(0); // uptr3 = nullptr; // *uptr3 = 1;

const auto みたいに書けば良かった…

Note: std::unique_ptrのconst参照渡し?

関数にconst参照渡しをする場合、その関数内で引数の値を書き換えられないことを期待している。
std::unique_ptrの先頭にconstをつけても格納されている値は書き換えられてしまうので要注意。
値を取り出してconst参照で渡すのが一番よさそう?

void Func(const A& a); auto a = std::make_unique<A>(); Func(*a);