エラー:XはCのこの関数で初期化せずに使用できます
-
06-07-2019 - |
質問
このエラーが発生しています
error: Access.Core may be used uninitialized in this function
これは私のコードです:
static int FirstTime = 1;
MyStruct Access;
if (FirstTime) {
FirstTime = 0;
Access = Implementation();
DoSomething(Access);
}
if(Other_Variable) {
Access = Implementation2();
DoSomething(Access);
}
//The Other_Variable will be set to 1 and to 0 by other part of the code
実装は関数実装を最初に呼び出すだけなので、私のコードはそのようです。呼び出しごとにAccess変数が更新されるため、あまり意味をなさないため、静的になります。
Accessを静的に動作させても、他のすべての呼び出しでAccessが更新されるため、静的にしたくない。静的にせずに問題を回避する方法はありますか。
また、静的変数を使用する代わりに関数を1回だけ実行するための優れたオプションも歓迎します。
解決
次のように Access
を作成(および FirstTime
と if
を削除):
static MyStruct Access = Implementation(this_b);
この警告が表示される理由は、静的変数が1回の関数呼び出しで生き残るためです。それらの値は、すべての関数呼び出しで保持されます(どのスレッドがその関数を呼び出すかに関係なくなし)。したがって、 FirstTime
は、 Access
を初期化するかどうかを制御します。コードが含まれている関数を初めて呼び出すと、 Access
変数が正しく初期化されます。しかし、さらに関数を呼び出すたびに、 FirstTime
はゼロになり、 は Access
を初期化しないため、コードの初期化されていない変数を使用します。 。
編集:ここで、更新された情報を使用して、2つの Implementation
関数があると言います。初めて使用する場合と、それ以外の場合は別の関数を使用する場合。これについてはどうですか:
// static will be false/zero by default
static bool AlreadyCalled;
MyStruct Access;
if (!AlreadyCalled) {
Access = Implementation();
AlreadyCalled = true;
} else {
Access = Implementation2();
}
実際のユースケースによっては、これを処理するより良い方法があるかもしれません。たとえば、次のように Access
の状態を更新しないのはなぜですか:
// let the default constructor initialize it
// to a plausible state
static MyStruct Access;
// use RAII to update the state of Access when this
// function returns.
MyUpdater updater(Access);
// now, do whatever the function does.
MyUpdater
のようなもの:
struct MyUpdater {
MyStruct &s;
MyUpdater(MyStruct &s):s(s) { }
~MyUpdater() {
s.ChangeState();
}
};
そのパターンは RAII
と呼ばれます:ローカルに割り当てられたオブジェクトのコンストラクターとデストラクターにいくつかの便利なアクションを関連付けます。
他のヒント
@litbの答えは興味深いです。 同等のプログラムが続きます。 コードはC ++で記述されているとおりにコンパイルおよび動作しますが、Cではコンパイルされません。
#include <stdio.h>
static int newval(void) { return 3; }
void inc(void)
{
static int a = newval();
a++;
printf("%d\n", a);
}
int main(void)
{
int i;
for (i = 0; i < 10; i++)
inc();
return(0);
}
gccのコメント:
x.c:関数 'inc'内: x.c:7:エラー:初期化子要素が定数ではありません
g ++は非常に満足しています。
これは、CとC ++の違いであり、気づいていませんでした(ただし、これは300文字に収まらないため、簡単にコメントにできません)。
@Eduardoはコメントの質問の1つを尋ねました:「なぜCはこれを許可しないのに、C ++は許可するのですか?」。 答えは300文字以上なので...
@litbがコメントで述べたように、Cでは静的変数の初期化子にのみ定数を使用できます。これは、値がmain()が呼び出される前に設定され、main()が呼び出される前にユーザー定義関数が呼び出されないためです。これに対して、C ++では、main()が呼び出される前にグローバル変数と静的変数を(ユーザー定義の)コンストラクターで初期化できるため、他のユーザー定義関数も呼び出さないようにする理由はないため、初期化は妥当です。 C89では、自動(ローカル)変数で使用できる初期化子に制限があります。 C99では、ほとんどすべての式を使用してローカル変数を初期化できます。
アクセスは静的ではないため、関数が呼び出されるたびに新しいインスタンスが作成されます。初めて初めて、実際に値を割り当てます。この値は、関数が終了するとすぐに失われます。
関数の呼び出し間でAccessを保持する必要がある場合は、静的にします。
Access
は静的ではないため、すべての呼び出しで作成する必要があります。
コードを次のように単純化することを検討してください:
static MyStruct Access = Implementation(this_b);
これにより、メソッドが最初に実行されたときにのみ関数が呼び出され、 Access
が呼び出し間で値を保持することが保証されます。