C++ Learning

第36回 確認問題(ライフサイクル)

STEP 5 のサイト最大の山場、ライフサイクル編の総合確認クイズ。全 12 問、カテゴリ別採点。

進め方

スコア 0 / 12 回答済み 0 ctor dtor/RAII copy move Rule
ctor コンストラクタ 0 / 2

Q1 コンストラクタが持てないのは?

引数
戻り値の型
オーバーロード
デフォルト引数
戻り値の型は書きません(オブジェクト自身が実質の戻り値)。引数・オーバーロード・デフォルト引数は可能。

Q2 次のメンバ変数で、初期化子リストが必須なのは?

int x_;
std::string s_;
std::vector<int> v_;
const int MAX_;
const は代入不可なので初期化子リストが唯一の初期化手段。参照メンバ(T&)、デフォルトコンストラクタを持たないクラス型メンバも同様。
dtor/RAII デストラクタと RAII 0 / 3

Q3 デストラクタが呼ばれるのはいつ?

プログラム終了時のみ
明示的に delete した時のみ
スコープを抜けた時や delete した時(オブジェクトが破棄される瞬間)
GC が動いた時
C++ にはガベージコレクタがなく、オブジェクトはスコープ終了(スタック)や delete(ヒープ)で決定的に破棄されます。この予測可能性が RAII の基礎。

Q4 次の順序で作られた 3 つのオブジェクトの破棄順序は?
{ Obj a; Obj b; Obj c; }

a → b → c
同時
c → b → a(逆順)
b → a → c
スコープ内の変数は作成と逆順(LIFO)で破棄されます。後から作ったものが先に壊れる。依存関係を逆順に解消できる設計。

Q5 RAII の中心的な考え方は?

メモリをヒープに取る
例外を投げない
資源取得をコンストラクタ、解放をデストラクタに
クラスを継承可能にする
RAII = Resource Acquisition Is Initialization。資源の取得と解放をオブジェクトの生存期間に結び付けることで、例外安全性と後始末忘れの防止を同時に達成。
copy コピー 0 / 2

Q6 Foo b = a; で呼ばれるのは?

コピー代入演算子
コピーコンストラクタ
ムーブコンストラクタ
通常のコンストラクタ
新規変数 b の初期化なのでコピーコンストラクタ。既存の b に b = a; の形ならコピー代入。左辺が既存か新規かで区別。

Q7 生ポインタで動的メモリを持つクラスに、コピーコンストラクタを自分で書かないとどうなる?

コンパイルエラー
深いコピーが自動で生成される
暗黙版が浅いコピーを行う(両者が同じヒープを指す → 二重解放)
実行時にエラーになる
暗黙のコピーコンストラクタはメンバを 1 つずつコピーするだけなので、ポインタ値だけがコピーされます。両者が同じヒープを指し、二重解放で未定義動作。Rule of Zero(STL 型でラップ)が最良の回避策。
move ムーブ 0 / 3

Q8 std::move(x) は実際に何をする?

x の中身を消す
x のコピーを作る
x を右辺値参照にキャストするだけ(実際の移動はしない)
x のアドレスを返す
std::move は実は何も動かさず、型を右辺値参照にキャストするだけ。実際の移動は受け取り側(ムーブコンストラクタなど)が行います。

Q9 ムーブコンストラクタに付けるべき修飾子は?

const
virtual
noexcept
inline
noexcept を付けないと、std::vector の再確保時にムーブではなくコピーにフォールバックされます。性能のために必須。

Q10 ムーブされた後のオブジェクトについて正しいのは?

もう存在しない
元の値をコピーで保持している
有効だが未定義の状態(STL 型なら通常は空)
自動で破棄される
有効だが未定義。アクセスは合法だが値に期待してはいけない。再代入するか、スコープ終了で破棄されるのを待ちます。
Rule Rule of 0/3/5 と総合 0 / 2

Q11 次のコードでムーブコンストラクタが暗黙生成されないのは?

class Foo { int x; };
class Foo { ~Foo(){} };
class Foo { std::vector<int> v; };
class Foo { };
デストラクタを自分で書くと、ムーブ 2 つが暗黙生成されなくなります。= default で明示的に復活させる必要があります。これが Rule of Zero を推奨する最大の理由。

Q12 次のコードで発生するコピーの数は? (C++17)
std::string make() { std::string s = "hi"; return s; }
std::string x = make();

2 回
1 回
ムーブ 1 回
0 回(RVO で省略)
C++17 以降はコピー省略が規格で強制されます。関数内の s は呼び出し側の x の場所で直接構築されるので、コピーもムーブも発生しません。

お疲れさまでした 🎉

0 / 12
次へ: STEP 6 スマートポインタ編