HOWTO · C++

C++ の new キーワードと No Match for Operator Error について

C++ の new キーワードの使い方と、使用中のよくある間違いの解決法についての簡単な記事です。

この記事では、C++ での new キーワードの使用について説明します。初心者のプログラマーは通常、new キーワードを使用しているときに多くの間違いを犯します。

また、彼らが犯す最も一般的なエラーのいくつかとそれらの潜在的な修正についても説明します。

C++ の new キーワード

new キーワードは、ヒープメモリにスペースを割り当てるようにオペレーティングシステムに要求する演算子として使用されます。その必要な量のメモリがヒープで使用可能な場合、それが割り当てられ、割り当てられ、初期化されたメモリのアドレスがポインタ変数に返されます。

new キーワードを使用するための構文は次のとおりです。

datatype pointer_variable_name = new datatype;

このデータタイプは、暗黙的なデータタイプまたは任意のクラス名にすることもできます。new キーワードを使用してクラスのポインタ変数を作成すると、クラスコンストラクタが呼び出され、メモリがヒープに割り当てられます。

new キーワードを使用せず、変数がスタックで初期化されている場合、その変数はスコープ外になると自動的に破棄されます。しかし、これはヒープ変数には当てはまりません。

ヒープ変数は自動的に破棄されません。むしろ、delete 演算子を使用して手動で破棄する必要があります。そうしないと、メモリにぶら下がってメモリリークの問題が発生します。

以下の例を見てみましょう。

#include <iostream>
using namespace std;

int main() {
  int *intPtr = new int;
  *intPtr = 10;
  cout << "Value of Integer pointer is: " << *intPtr << endl;
  delete intPtr;
  return 0;
}

出力:

Value of Integer pointer is: 10

C++ の new キーワードに関する一般的なエラー

特定の状況では、プログラマーはそれを正しいデータで初期化せず、割り当てられていないデータを使用します。その結果、プログラムの実行を妨げる可能性のある未知または不要なデータが発生します。たとえば、次の 2つの状況があります。

int *ptr = new int;      // situation 1
int *ptr2 = new int[5];  // situation 2

最初の状況では、メモリは単一の変数に割り当てられ、2 番目の状況では、メモリは 5 の整数変数に割り当てられます。つまり、5つのインデックスの配列がヒープ上に作成されます。

最初の状況を使用してポインタを宣言することにより、ptr[3] にアクセスするとします。その場合、未割り当てのスペースにアクセスしているため、そのメモリ位置に以前に何が配置されていたかがわからないため、不明なエラーが発生する可能性があります。

したがって、ヒープに割り当てられたメモリを割り当てて使用するときは、細心の注意を払う必要があります。

クラスへのポインタがあり、クラスオブジェクトの配列を作成する必要がある状況を考えてみます。

class Students {
  int roll_num;
  string name;
};
int main() {
  Students *student_list = new Students[10];
  for (int k = 0; k < 10; k++) {
    student_list[k] = new Students();  // line 10
  }
}

上記のコードスニペットの 10 行目では、配列の各インデックスでオブジェクトを初期化しています。ただし、この行では次のようなエラーが発生します。

/tmp/qqnmmMnApj.cpp: In function 'int main()':
/tmp/qqnmmMnApj.cpp:14:40: error: no match for 'operator=' (operand types are 'Students' and 'Students*')
   14 |         student_list[k] = new Students();
      |                                        ^

これは、配列 student_list のすべてのインデックスが Students クラスのオブジェクトであり、Students クラスのポインタではないためです。したがって、初期化するために new キーワードは必要ありません。

次のように初期化する必要があります。

student_list[k] = Students();

もう 1つの一般的なエラーは、すでに削除または解放されているメモリ位置にアクセスすることです。一部の関数が delete 演算子を使用して割り当てられたメモリをヒープから割り当て解除し、プログラムの他のポイントでその場所にアクセスしようとする特定の状況があります。

これはエラーを引き起こす可能性があり、特に大規模なプロジェクトで作業している場合は、追跡が非常に困難です。以下の例を考えてみましょう。

int main() {
  int *p = new int;
  *p = 5;
  cout << "before deletion: " << *p << endl;
  delete p;
  cout << "After deletion: " << *p << endl;
}

出力:

before deletion: 5
After deletion: 0

出力を見ると、削除後、値がメモリから消去されていることがわかります。したがって、ゼロを返します。大規模なプロジェクトでは、解放されたメモリ位置が他のプログラムによって取得され、プログラムロジックを妨害する可能性のある他のデータが含まれている場合があるため、実行時に不要なエラーが発生する可能性があります。