はじめに
Effective C++ 第3版の4項23ページから勉強していきます。
今回は、「異なるコンパイル単位で定義されたローカルでない静的オブジェクトの初期化」についです。
Effective C++ 第3版 - 4項 オブジェクトは、使う前に初期化しよう -
異なるコンパイル単位で定義されたローカルでない静的オブジェクトの初期化
ローカルでない静的オブジェクトとは?
「静的なオブジェクト」とは、生成されてからプログラムが終了するまで存在し続けるオブジェクトのことです。
ここで言う「ローカルでない静的なオブジェクト」とは、グローバルなオブジェクト、名前空間をスコープとするオブジェクト、
クラス内でstatic宣言されたオブジェクト、そしてファイル内でstatic宣言されたオブジェクトのことを指す。
ローカルでない静的オブジェクトの初期化の順番
ローカルでない静的オブジェクトの初期化の順番は未定義です。
そのため、あるファイルでは、ローカルでない静的なオブジェクトの宣言をし、
その宣言したオブジェクトを別のファイルで使う場合は、注意が必要です。
以下に、externを使った例を示します。
# ifndef EXTERN_1_H
# define EXTERN_1_H
# include <iostream>
// このファイルは、FileSystemクラスの宣言のみを行う
class FileSystem {
public:
FileSystem();
std::size_t numDisks() const;
};
# endif /* EXTERN_1_H */
# include "4_extern_1.hpp"
// このファイルは、FileSystemの定義のみを行う
FileSystem::FileSystem(){};
std::size_t FileSystem::numDisks() const { return 3; };
# include "4_extern_1.hpp"
// このファイルでは、使用するローカルでないオブジェクトの宣言のみを行う
FileSystem tfs; // コンパイルが通らない
int a; // コンパイルが通る
# ifndef EXTERN_4_H
# define EXTERN_4_H
# include <iostream>
# include "4_extern_1.hpp"
// クラスDirectoryの宣言のみ行う
class Directory {
public:
Directory();
};
# endif /* EXTERN_4_H */
# include "4_extern_4.hpp"
// クラスDirectory の定義を行う
extern FileSystem tfs;
Directory::Directory() { std::size_t disks = tfs.numDisks(); }
# include "4_extern_1.hpp"
# include "4_extern_4.hpp"
Directory directory_g1();
extern FileSystem tfs;
extern int a;
Directory directory_g2();
int main(int argc, char* []) {
std::cout << "4_extern" << std::endl;
Directory directory();
std::cout << tfs.numDisks() << std::endl;
}
本では、
「ローカルでない静的なオブジェクト」のうち1つが、別のコンパイル単位の「ローカルでない静的オブジェクト」を初期化するために
使われていた場合、初期化は行わないかもしれないのです。
と言うのは、「異なる翻訳単位にあるローカルでない静的なオブジェクト」の初期化の順番は決められていないからです。
と書いてありました。
そのため、
ローカルでない静的なオブジェクトである directory_g1 と directory_g2は、コンストラクタ内で、ローカルな静的オブジェクト tfs を使用しているので、初期化する前にアクセスされる可能性がある。
そのため、バグがでると思ったんですが特にありませんでした。
この部分は、とても理解に苦しみました。
本当にあってるか分かりません。ごめんなさい。
以下に、勉強で使用したコードを示します。
サンプルコード
上のコードと同じ
実行結果
コンパイルできなかった。
参考文献
・https://www.amazon.co.jp/gp/product/4621066099/ref=dbs_a_def_rwt_hsch_vapi_taft_p1_i0