どこで使うのがよいですかマクロそしてどこを優先すべきかコンストラクター? 基本的には同じではないでしょうか?
#define MAX_HEIGHT 720
対
constexpr unsigned int max_height = 720;
ベストアンサー1
基本的には同じではないでしょうか?
いいえ。絶対に違います。全然違います。
int
マクロが であり、 が でconstexpr unsigned
あるという事実以外にもunsigned
、重要な違いがあり、マクロには1つアドバンテージ。
範囲
マクロはプリプロセッサによって定義され、発生するたびにコードに置き換えられます。プリプロセッサはバカC++ の構文やセマンティクスを理解しません。マクロは名前空間、クラス、関数ブロックなどのスコープを無視するため、ソース ファイル内の他のものに名前を使用することはできません。これは、適切な C++ 変数として定義された定数には当てはまりません。
#define MAX_HEIGHT 720
constexpr int max_height = 720;
class Window {
// ...
int max_height;
};
max_height
データ メンバーはクラス メンバーであるため、スコープが異なり、名前空間スコープのものとは異なるため、データ メンバーを呼び出すことは問題ありません。MAX_HEIGHT
メンバーの名前を再利用しようとすると、プリプロセッサによってコンパイルできない次のような意味不明な名前に変更されます。
class Window {
// ...
int 720;
};
このため、マクロが目立つようにし、衝突を避けるためにマクロ名に注意する必要がありますUGLY_SHOUTY_NAMES
。マクロを不必要に使用しない場合は、そのことを心配する必要はありません (また、 を読む必要もありませんSHOUTY_NAMES
)。
関数内に定数だけが必要な場合、マクロではそれができません。プリプロセッサは関数が何であるか、または関数内に存在することが何を意味するかを認識していないためです。マクロをファイルの特定の部分のみに制限するには、次のように#undef
再度実行する必要があります。
int limit(int height) {
#define MAX_HEIGHT 720
return std::max(height, MAX_HEIGHT);
#undef MAX_HEIGHT
}
はるかに賢明な例と比較してみましょう:
int limit(int height) {
constexpr int max_height = 720;
return std::max(height, max_height);
}
なぜマクロの方が好ましいのでしょうか?
本当の記憶の場所
constexpr変数変数であるつまり、実際にプログラム内に存在し、そのアドレスを取得して参照をバインドするなど、通常の C++ の処理を実行できます。
このコードの動作は未定義です:
#define MAX_HEIGHT 720
int limit(int height) {
const int& h = std::max(height, MAX_HEIGHT);
// ...
return h;
}
問題は、 がMAX_HEIGHT
変数ではないため、 の呼び出しのためにコンパイラによってstd::max
一時ファイルint
が作成されなければならないことです。 によって返される参照は、std::max
そのステートメントの終了後には存在しない一時ファイルを参照する可能性があるため、return h
無効なメモリにアクセスします。
適切な変数の場合は、消えることのないメモリ内の固定された場所があるため、この問題は発生しません。
int limit(int height) {
constexpr int max_height = 720;
const int& h = std::max(height, max_height);
// ...
return h;
}
(実際にはおそらくint h
そうではないと宣言するでしょうconst int& h
が、より微妙な状況で問題が発生する可能性があります。)
プリプロセッサ条件
マクロを使用するべき唯一のケースは、条件で使用するためにプリプロセッサがその値を理解する必要がある場合です#if
。例:
#define MAX_HEIGHT 720
#if MAX_HEIGHT < 256
using height_type = unsigned char;
#else
using height_type = unsigned int;
#endif
プリプロセッサは名前で変数を参照する方法を理解していないため、ここで変数を使用することはできません。プリプロセッサは、マクロ展開や で始まるディレクティブ#
(およびなど#include
)などの非常に基本的なことだけを理解します。#define
#if
定数が必要な場合はプリプロセッサが理解できるプリプロセッサを使用して定義する必要があります。通常の C++ コード用の定数が必要な場合は、通常の C++ コードを使用します。
上記の例はプリプロセッサの条件を示すためのものですが、そのコードでもプリプロセッサの使用を回避できます。
using height_type = std::conditional_t<max_height < 256, unsigned char, unsigned int>;