C言語のコンパイラエラー C2073の原因と修正方法について解説
この記事では、Visual Studioで発生するコンパイラ エラー C2073について説明します。
ユーザー定義型の配列で初期化子が不足し、既定のコンストラクターが呼び出されない場合にエラーが発生します。
具体例を交えながら、原因と修正方法をわかりやすく解説します。
エラーの背景と発生条件
C2073エラーの基本説明
C2073エラーは、ユーザー定義型や定数の配列を初期化する際に、初期化子が不足している場合に発生するエラーです。
具体的には、配列の各要素に対して明示的な初期化子やそれに対応するコンストラクタが指定されていない場合に発生します。
たとえば、クラスに既定のコンストラクタが定義されていないと、配列の一部だけ初期化しようとするとこのエラーが起こります。
初期化不足による発生条件
配列の宣言時に要素数よりも少ない初期化子しか指定していない場合、コンパイラは残りの要素の初期化方法を判断できません。
そのため、各要素に対して既定のコンストラクタが必要です。
もしクラスが既定のコンストラクタを持たない場合、配列の部分初期化は失敗し、C2073エラーが発生します。
たとえば、以下の条件ではエラーが発生する可能性があります。
- ユーザー定義型のクラスが既定のコンストラクタを持たない
- 配列の要素数が初期化子の個数を上回っている
コード例によるエラー現象の確認
エラーを引き起こすコード例の紹介
次に示すコードは、初期化子が不足しているためにC2073エラーが発生する例です。
クラスA
において、int
型専用のコンストラクタしか定義されていないため、配列要素の一部が初期化されずエラーになります。
初期化子不足による問題点
以下のコード例では、配列aArray
の3要素のうち2要素しか初期化されていません。
クラスA
に既定のコンストラクタが定義されていないため、残りの1要素の初期化方法が不明となり、エラーC2073が発生します。
// C2073.cpp
#include <iostream>
using namespace std;
class A {
public:
// int型用のコンストラクタのみ定義
A(int value) {
cout << "A(" << value << ") が呼び出されました" << endl;
}
};
// 配列の3要素のうち、2要素分のみ初期化を行っているためエラーが発生
A aArray[3] = { A(1), A(2) };
int main() {
return 0;
}
// コンパイルエラー C2073: 部分的に初期化された配列の要素には、既定のコンストラクターを指定しなければなりません
エラー内容の詳細な説明
エラーC2073は、コンパイラが配列の全要素を正しく初期化する方法が見つからない場合に発生します。
特に、明示的な初期化子が欠けている場合や、クラスに既定のコンストラクタが定義されていない場合に注意が必要です。
このエラーは、各配列要素を初期化するための手段が不足していることを示しており、配列全体の初期化方法について再検討する必要があることを教えてくれます。
エラー修正の具体的な方法
修正アプローチの概要
エラーを解決するためには、次の2つのアプローチが考えられます。
- クラスに既定のコンストラクタを追加して、配列のすべての要素を正しく初期化できるようにする。
- 配列に対して必要な要素すべてを明示的に初期化子として指定する。
どちらの方法も、各要素の初期化を完全にすることによりエラーを回避します。
デフォルトコンストラクタの追加方法
クラスに既定のコンストラクタを追加することで、配列の全要素が初期化されるようにします。
以下のサンプルコードは、クラスB
に既定のコンストラクタを定義し、配列bArray
の不足している要素も初期化可能にしています。
// C2073b.cpp
#include <iostream>
using namespace std;
class B {
public:
// 既定のコンストラクタを定義
B() {
cout << "Bの既定コンストラクタが呼び出されました" << endl;
}
// int型用のコンストラクタも定義
B(int value) {
cout << "B(" << value << ") が呼び出されました" << endl;
}
};
// 配列の3要素のうち、2要素のみ明示的に初期化を行っても、残りは既定のコンストラクタで初期化される
B bArray[3] = { B(1), B(2) };
int main() {
// 配列の初期化の呼び出しを確認できます
return 0;
}
B(1) が呼び出されました
B(2) が呼び出されました
Bの既定コンストラクタが呼び出されました
初期化子の適切な指定方法
もう一つの方法は、配列に必要なすべての要素を明示的に初期化子として指定する方法です。
全要素に対して初期化処理を記述することで、エラーを防ぐことができます。
下記のサンプルコードは、クラスA
を使用して配列の全要素に対して初期化子を指定した例です。
// C2073_fix.cpp
#include <iostream>
using namespace std;
class A {
public:
// int型専用のコンストラクタのみ定義
A(int value) {
cout << "A(" << value << ") が呼び出されました" << endl;
}
};
// 配列の全3要素に対して初期化子を明示的に指定する
A aArray[3] = { A(1), A(2), A(3) };
int main() {
// 各要素の初期化確認のための処理
return 0;
}
A(1) が呼び出されました
A(2) が呼び出されました
A(3) が呼び出されました
Visual Studio環境での現状と違い
Visual Studio 2022での動作変更
Visual Studio 2022以降では、かつて発生していたC2073エラーに関連する動作が変更されました。
新しいバージョンでは、一部のケースにおいて、コンパイラ自身が部分的な初期化に対して柔軟に対応できるようになっており、従来のようなエラーが発生しない場合もあります。
この変更により、既定のコンストラクタの欠如が致命的なエラーとならず、プログラムのコンパイルが進む可能性がありますが、正確な動作や警告がどのように扱われるかはプロジェクトの設定やコードの内容に依存します。
旧バージョンとの比較ポイント
旧バージョンのVisual Studioでは、クラスに既定のコンストラクタが存在しない場合の配列初期化に対して厳格にエラーが発生していました。
一方、Visual Studio 2022では以下の点が変更されています。
- 部分的な初期化に対して、コンパイラが自動的に適切な初期化方法を補う場合がある。
- 初期化子不足でも明示的なエラーが発生しないケースが見られる。
このため、古い環境でのエラー解消方法が新しい環境では必ずしも必要ではなくなる場合がありますが、コードの移植性や再利用性を考慮して明確な初期化を行うことが推奨されます。
まとめ
この記事では、C2073エラーの原因とその発生条件について理解できる内容となっています。
具体的には、クラスに既定のコンストラクタが定義されていない場合や明示的な初期化子が不足している場合にエラーが発生する仕組みを、実際のコード例を通して説明しました。
また、エラー修正の方法として、既定のコンストラクタの追加やすべての要素に対して初期化子を指定する手法を紹介し、Visual Studio 2022での動作変更と旧バージョンとの比較も行っています。