C言語のC2830エラー:operator new標準仮引数に既定値が指定できない理由について解説
この記事は、C言語やC++で開発する際に発生するc2830エラーについて簡単に解説します。
Microsoftコンパイラで、operator new
の標準パラメーターに既定値を設定しようとするとエラーが出ます。
ユーザー定義の配置パラメーターには既定値を指定できる仕様ですので、コード記述時に注意してください。
エラーメッセージの解析
エラー C2830の内容
コンパイラ エラー C2830は、operator new
の標準の仮引数に既定値を指定しようとした場合に発生するエラーです。
Microsoftのコンパイラでは、標準の配置用パラメーターに既定値を与えることは認められておらず、そのため上記のようなコードがコンパイルエラーとなります。
エラーメッセージには「’operator new’ の標準の仮引数には既定の値を与えることはできません」と表示され、該当部分を修正する必要があると示されます。
‘operator new’における標準仮引数と既定値仕様
C++では、メモリ割り当てのためにoperator new
が用いられ、その宣言は標準ライブラリにより提供されています。
しかし、標準で定義されたoperator new
の仮引数については、既定値を指定することが認められていません。
一方で、ユーザーが定義する配置(placement)パラメーターは既定値の設定が可能です。
つまり、既定値を指定できるのは、ユーザー定義の配置パラメーターに限られ、標準の仮引数に対しては適用できない仕様となっています。
operator newの仕様と実装
C/C++におけるnew演算子の基本動作
C++では、new
演算子を使用して動的にメモリを確保し、コンストラクタを呼び出す動作が行われます。
new
演算子は内部でoperator new
関数を呼び出すことでメモリ割り当てを実施し、割り当てが成功すると指定した型のオブジェクトを生成します。
以下のサンプルコードは、基本的なnew
演算子の動作例です。
#include <iostream>
#include <new> // operator new の宣言が含まれる
int main() {
// new演算子で整数オブジェクトの動的生成を行う
int* pInt = new int(42);
std::cout << "生成した値: " << *pInt << std::endl;
delete pInt; // メモリの解放
return 0;
}
生成した値: 42
この例では、new
演算子によって整数のメモリを確保し、その領域に初期値を設定した後、値を出力しています。
標準パラメーターとユーザー定義配置パラメーターの違い
operator new
にはメモリの割り当て方法を制御するために、通常の標準パラメーターとユーザー定義の配置パラメーターがあります。
・標準パラメーターはライブラリ側で定義され、既定値を指定することができません。
・ユーザー定義の配置パラメーターでは、開発者が必要に応じて仮引数に既定値を設定することが可能です。
この違いにより、既定値の指定が許されるか否かが異なり、ユーザーが作成するカスタムなメモリアロケーション処理では柔軟な引数設定ができる一方、標準の部分では仕様に厳格な制約が課されています。
Microsoftコンパイラの実装特徴
Microsoftのコンパイラは、標準で提供されるoperator new
関数に対して、厳密に設計された仕様を適用しています。
具体的には、標準の仮引数に対して既定値を設定しようとするコードはコンパイル時にエラーとして検出されます。
この実装は、意図しない既定値の混入や、メモリ割り当ての標準動作に対する改変を防ぐためのものであり、ユーザー定義の配置パラメーター(例えば、カスタムタグを用いる配置new)についてのみ、既定値の設定を認めています。
エラー発生の原因
誤った既定値設定のコード例
標準のoperator new
の仮引数に既定値を指定してしまうと、コンパイラ エラー C2830が発生します。
以下のサンプルコードは、誤った既定値の設定例を示しています。
#include <new>
#include <cstdlib>
#include <iostream>
// この定義はエラー C2830 を引き起こす
void* operator new(std::size_t size, const std::nothrow_t& tag = std::nothrow) { // エラー発生箇所
// 標準の仮引数に既定値を与えているため不正
return std::malloc(size);
}
int main() {
// コンパイラは上記の既定値指定に対してエラーを出力します
int* pInt = new(std::nothrow) int(100);
std::cout << *pInt << std::endl;
std::free(pInt);
return 0;
}
(コンパイルエラー:'operator new' の標準の仮引数には既定値を与えることはできません)
このように、標準の仮引数に既定値を与えると、Microsoftのコンパイラは仕様違反として明確にエラーを検出します。
コンパイラによるチェックのポイント
コンパイラは、operator new
の宣言部分を解析する際、以下の点を重点的にチェックしています。
・引数の型が標準で定義されているかどうか
・標準の仮引数に既定値が指定されていないかどうか
・ユーザー定義の配置パラメーターの場合、既定値の設定が許容されるかどうか
これらのチェックにより、不正な既定値設定があれば即座にエラーとして通知し、正しいメモリ割り当て処理が行われるようになっています。
エラー修正例
正しい記述方法の検証
エラー修正としては、標準の仮引数部分から既定値の指定を削除し、もしユーザー定義の配置パラメーターに既定値を与える必要がある場合は、それが許容される構文で記述することが求められます。
以下のサンプルは、正しい記述方法を検証するための例です。
標準仮引数の使い方
標準のoperator new
に対しては、既定値を指定することなく、コンパイラやライブラリで定められたシグネチャに従った記述を行います。
既定値の指定が不要であるため、宣言はシンプルに記述します。
正しい例として、標準の新演算子は以下のように定義されています。
ユーザー側でこの定義を変更することはできませんが、標準側の仕様に従った使い方をする必要があります。
#include <iostream>
#include <new>
int main() {
// 標準のnew演算子の使用例
int* pInt = new int(200);
std::cout << "生成した値: " << *pInt << std::endl;
delete pInt;
return 0;
}
生成した値: 200
ユーザー定義配置パラメーターの設定方法
ユーザー定義の配置newにおいては、既定値の指定が可能です。
例えば、独自のタグ型を定義し、そのタグを利用して配置newを実装する場合は、以下のように記述します。
#include <new>
#include <cstdlib>
#include <iostream>
// ユーザー定義タグ型の宣言
struct CustomTag {};
// ユーザー定義配置newの実装
void* operator new(std::size_t size, CustomTag tag = CustomTag{}) {
// ユーザー定義の既定値付き配置newは許容される
return std::malloc(size);
}
int main() {
// CustomTagを使ってオブジェクトを生成
int* pInt = new(CustomTag{}) int(300);
std::cout << "ユーザー定義配置newで生成した値: " << *pInt << std::endl;
std::free(pInt);
return 0;
}
ユーザー定義配置newで生成した値: 300
この例では、CustomTag
というユーザー定義のタグ型を用いて、operator new
をオーバーロードしています。
仮引数に既定値を設定しているため、呼び出し側でタグを省略することも可能ですが、場合によっては明示的に指定することで意図を明確にできます。
以上のように、標準の仮引数には既定値を指定せず、ユーザー定義の配置パラメーターでのみ既定値を設定することで、エラー C2830を回避する正しい記述方法が実現できます。
まとめ
本記事では、Microsoftコンパイラで発生するエラー C2830 の原因と対応方法について解説しています。
標準の operator new の仮引数に既定値を指定できない理由や、ユーザー定義配置パラメーターで既定値を指定できる点を具体的なコード例を交えて説明しました。
これにより、正しい記述方法およびエラー回避方法が理解できる内容となっています。