static const
プリプロセッサよりも#define
varsを使用する方が良いですか?それともコンテキストに依存しますか?
各方法の長所と短所は何ですか?
個人的には、プリプロセッサが嫌いなので、常にconstを使います。
#defineの主な利点は、実際にテキストをリテラル値に置き換えるだけであるため、プログラムに保存するためのメモリを必要としないことです。また、型がないという利点もあるため、警告を生成せずに任意の整数値に使用できます。
「定数」の利点は、スコープを設定できることと、オブジェクトへのポインターを渡す必要がある状況で使用できることです。
しかし、「静的」な部分で何が得られるのか正確にはわかりません。グローバルに宣言する場合は、静的を使用する代わりに、匿名の名前空間に配置します。例えば
namespace {
unsigned const seconds_per_minute = 60;
};
int main (int argc; char *argv[]) {
...
}
用途に応じて、すべての長所と短所:
enum class X
の列挙がスコープX::
によって明確にされるC++ 11 enumクラスでうまく処理されますint
ですが、プログラマは明示的に設定できますtemplate <typename T> void f(T t) { cout << ++t; }
はコンパイルされませんが、暗黙のコンストラクター、キャスト演算子、ユーザー定義演算子を使用して列挙型をクラスにラップできます)template <typename T> void f(T)
は、異なる列挙型から同じ数値を渡されたときに異なるインスタンス化を取得します。これらはすべて、実際のf(int)
インスタンス化とは異なります。各関数のオブジェクトコードは同一である可能性があります(アドレスオフセットは無視されます)が、コンパイラー/リンカーが不要なコピーを削除することは期待していませんが、コンパイラー/リンカーを確認することはできます。enum { A = 1, B = 2 }
-はA|B
からの「合法」ですプログラムロジックの視点?)make
およびその他のタイムスタンプベースの再コンパイルツールは、変更時にクライアントの再コンパイルをトリガーします(不良!)#define
ala #define S std::string("abc")
を「タイプ」しようとするかもしれませんが、定数は使用の各ポイントで異なる一時的なものの繰り返しの構築を避けますconst
以外の値に最も似ており、2つを切り替える場合の作業と影響を最小限に抑えます#define X "x"
といくつかのクライアントの使用法が"pre" X "post"
である場合、Xを定数ではなくランタイム変更可能な変数にしたい、または必要とする場合、クライアントコードを(単に再コンパイルするのではなく)強制的に編集しますが、その遷移はconst char*
から簡単ですまたは、ユーザーに連結操作を組み込むことを既に強制している場合は、const std::string
(たとえば、string
の場合は"pre" + X + "post"
)sizeof
を直接使用することはできませんunsigned
と比較してもGCCは警告しません){ 1, 2 }
や#define MICROSECONDS *1E-6
などの「定数」を作成します(definitelyこれはお勧めしません!)__FILE__
や__LINE__
などの特別なものをマクロ置換に組み込むことができます#if
ステートメントの存在と値をテストできます(プリプロセッサによって選択されない場合、コードをコンパイルする必要がないため、ポストプリプロセスの「if」よりも強力です)、#undef
- ine、再定義などを使用します.make
およびその他のタイムスタンプベースの再コンパイルツールは、変更時にクライアントの再コンパイルをトリガーします(悪い!)一般的なルールとして、私はconst
sを使用し、それらを一般的な使用のための最もプロフェッショナルなオプションと考えます(ただし、他の人はこの古い怠け者のプログラマーに魅力的なシンプルさを持っています)。
これがC++の質問であり、代替として#define
に言及している場合、それはクラスメンバーではなく「グローバル」(つまりファイルスコープ)定数に関するものです。 C++のそのような定数に関してはstatic const
は冗長です。 C++では、const
にはデフォルトで内部リンケージがあり、static
を宣言しても意味がありません。つまり、実際にはconst
対#define
についてです。
そして最後に、C++ではconst
が望ましいです。少なくとも、そのような定数は型指定されスコープされているためです。いくつかの例外を除き、const
よりも#define
を好む理由はまったくありません。
文字列定数BTWは、このような例外の一例です。 #define
d文字列定数を使用すると、C/C++コンパイラのコンパイル時の連結機能を次のように使用できます。
#define OUT_NAME "output"
#define LOG_EXT ".log"
#define TEXT_EXT ".txt"
const char *const log_file_name = OUT_NAME LOG_EXT;
const char *const text_file_name = OUT_NAME TEXT_EXT;
追伸繰り返しますが、念のために、誰かがstatic const
を#define
の代替として言及するとき、それは通常、彼らがC++ではなくCについて話していることを意味します。この質問は適切にタグ付けされているのだろうか...
静的constを使用することは、コードで他のconst変数を使用することに似ています。これは、プリコンパイルプロセスでコード内で単純に置き換えられる#defineとは対照的に、情報がどこから来てもトレースできることを意味します。
この質問については、C++ FAQ Liteをご覧ください。 http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.7
通常、静的constを優先する必要があります。欠点はありません。 prprocessorは、主に条件付きコンパイルに使用する必要があります(場合によっては、非常にダーティなトリックにも使用します)。
プリプロセッサディレクティブ#define
を使用して定数を定義することは、C++
だけでなくC
にも適用することはお勧めしません。これらの定数には型がありません。 C
でさえ、定数にconst
を使用することが提案されました。
こちらをご覧ください: static const vs define
通常はconst宣言(静的である必要はないことに注意してください)
プリプロセッサなどのいくつかの追加ツールよりも、常に言語機能を使用することをお勧めします。
ES.31:定数または「関数」にマクロを使用しないでください
マクロはバグの主な原因です。マクロは、通常のスコープとタイプの規則に従いません。マクロは、引数を渡すための通常の規則に従いません。マクロは、人間の読者がコンパイラが見るものとは異なるものを見るようにします。マクロはツールの構築を複雑にします。
From C++ Core Guidelines
#define
は予期しない結果につながる可能性があります。
#include <iostream>
#define x 500
#define y x + 5
int z = y * 2;
int main()
{
std::cout << "y is " << y;
std::cout << "\nz is " << z;
}
誤った結果を出力します:
y is 505
z is 510
ただし、これを定数に置き換えた場合:
#include <iostream>
const int x = 500;
const int y = x + 5;
int z = y * 2;
int main()
{
std::cout << "y is " << y;
std::cout << "\nz is " << z;
}
正しい結果を出力します:
y is 505
z is 1010
これは、#define
が単にテキストを置き換えるためです。これを行うと、操作の順序が著しく損なわれる可能性があるため、代わりに定数変数を使用することをお勧めします。
クラスのすべてのインスタンス間で共有される定数を定義する場合は、静的constを使用します。定数が各インスタンスに固有の場合は、constを使用します(ただし、クラスのすべてのコンストラクターは、初期化リストでこのconstメンバー変数を初期化する必要があります)。