C++において、配列はデータを格納するための基本的なデータ構造です。しかし、従来のCスタイルの配列は、コンパイル時にサイズが決定される静的配列であり、プログラム実行中にサイズを変更することができません。これは、プログラムの柔軟性を大きく制限する要因となります。
そこで登場するのが、std::vector
のような動的配列です。std::vector
は、プログラムの実行中に必要に応じてサイズを拡張または縮小できるため、メモリを効率的に利用し、より柔軟なデータ構造を構築できます。
特に、データの数が事前にわからない場合や、プログラムの実行中にデータの数が変化する場合には、動的配列の利用が不可欠となります。例えば、外部ファイルからデータを読み込む場合や、ユーザーからの入力を処理する場合などが挙げられます。
std::vector
が提供するpush_back
メソッドは、動的配列の末尾に要素を追加するための非常に便利な機能です。これにより、配列のサイズを気にすることなく、簡単に要素を追加していくことができます。
本記事では、C++におけるpush_back
メソッドの基本的な使い方から、配列をpush_back
する際の注意点、パフォーマンスの考慮、多次元配列への応用など、push_back
を活用して動的配列を効果的に扱う方法について詳しく解説していきます。
std::vector
は、C++の標準テンプレートライブラリ(STL)に含まれる、動的配列を実現するためのコンテナです。従来のCスタイルの配列とは異なり、std::vector
はプログラムの実行中にサイズを変更できるため、より柔軟なデータ管理が可能です。
push_back
は、std::vector
のメンバ関数の一つで、vector
の末尾に新しい要素を追加するために使用されます。この操作により、vector
のサイズが自動的に拡張され、追加された要素を格納するためのメモリが確保されます。
push_back
は、非常にシンプルで使いやすい関数です。以下に基本的な使い方を示します。
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers; // 整数のvectorを宣言
numbers.push_back(10); // 末尾に10を追加
numbers.push_back(20); // 末尾に20を追加
numbers.push_back(30); // 末尾に30を追加
// vectorの内容を表示
for (int number : numbers) {
std::cout << number << " ";
}
std::cout << std::endl; // 出力: 10 20 30
return 0;
}
この例では、int
型の要素を格納するstd::vector
を宣言し、push_back
メソッドを使って3つの整数を末尾に追加しています。ループを使ってvector
の内容を表示すると、追加された要素が順番に出力されることがわかります。
push_back
メソッドは、以下の手順で動作します。
-
要素のコピーまたはムーブ:
push_back
に渡された要素がvector
にコピーまたはムーブされます。コピーコンストラクタまたはムーブコンストラクタが呼び出されます。 -
サイズの調整: 必要に応じて、
vector
のサイズが拡張されます。現在の容量を超える要素が追加される場合、vector
はより大きなメモリ領域を新たに確保し、既存の要素を新しい領域にコピーしてから、新しい要素を追加します。 -
要素の追加: 新しい要素が
vector
の末尾に追加されます。
- 動的なサイズ調整: プログラムの実行中に要素数を増減できるため、柔軟なデータ管理が可能です。
-
簡単な操作: 要素の追加が
push_back
メソッドを呼び出すだけで簡単に行えます。 -
メモリ管理の自動化:
vector
がメモリの確保と解放を自動的に行うため、メモリリークのリスクを軽減できます。
push_back
は、std::vector
を使う上で非常に重要なメソッドです。動的配列の利点を最大限に活かし、効率的なプログラミングを実現するために、push_back
の基本的な使い方を理解しておくことが重要です。
std::vector
のpush_back
メソッドは非常に便利ですが、配列(特にCスタイルの固定長配列)をpush_back
する際には、いくつかの注意点があります。誤った使い方をすると、コンパイルエラーや実行時エラーを引き起こす可能性があります。
push_back
に渡す型は、std::vector
の要素の型と一致している必要があります。Cスタイルの配列をそのままpush_back
しようとすると、型が一致しないためコンパイルエラーが発生します。
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers;
int myArray[] = {1, 2, 3};
// エラー:型が一致しない
// numbers.push_back(myArray); // コンパイルエラー
return 0;
}
この例では、std::vector<int>
はint
型の要素を格納するように定義されていますが、push_back
に渡そうとしているのはint
型の配列myArray
です。これは型が一致しないため、コンパイルエラーとなります。
配列全体をstd::vector
に追加したい場合は、配列の要素を一つずつpush_back
する方法以外にも、std::vector
のコンストラクタやinsert
メソッドを利用することができます。
#include <iostream>
#include <vector>
int main() {
int myArray[] = {1, 2, 3};
int arraySize = sizeof(myArray) / sizeof(myArray[0]);
// 方法1:コンストラクタを利用
std::vector<int> numbers(myArray, myArray + arraySize);
// 方法2:insertメソッドを利用
std::vector<int> numbers2;
numbers2.insert(numbers2.end(), myArray, myArray + arraySize);
// vectorの内容を表示(どちらの方法でも同じ結果)
for (int number : numbers) {
std::cout << number << " ";
}
std::cout << std::endl; // 出力: 1 2 3
return 0;
}
この例では、std::vector
のコンストラクタに配列の開始アドレスと終了アドレスを渡すことで、配列全体をコピーして初期化しています。また、insert
メソッドを使うことでも同様の結果が得られます。
std::vector
がポインタを格納するように定義されている場合、配列の先頭アドレス(ポインタ)をpush_back
することができます。ただし、この場合、vector
には配列のコピーではなく、配列へのポインタが格納されることに注意が必要です。
#include <iostream>
#include <vector>
int main() {
int myArray[] = {1, 2, 3};
std::vector<int*> pointers;
pointers.push_back(myArray); // 配列の先頭アドレスをpush_back
// ポインタを使って配列の要素にアクセス
std::cout << *pointers[0] << std::endl; // 出力: 1
return 0;
}
この例では、std::vector<int*>
はint
型へのポインタを格納するように定義されています。push_back
に配列myArray
の先頭アドレスを渡すことで、vector
に配列へのポインタが格納されます。
注意点:
- ポインタを
push_back
する場合、元の配列の寿命がvector
よりも短いと、不正なメモリにアクセスする可能性があります。 -
vector
が所有権を持つようにする場合は、配列のコピーを格納するようにしましょう。
push_back
は、要素をコピーしてvector
に追加します。要素の型が複雑なオブジェクトである場合、コピーコストが高くなる可能性があります。このような場合は、emplace_back
メソッドを使うことで、コピーを避けることができます。(emplace_back
については後述)
配列をpush_back
する際には、型の不一致、配列全体のコピー、ポインタの扱い、コピーコストなどに注意する必要があります。適切な方法を選択することで、効率的かつ安全にstd::vector
を活用することができます。
ここでは、std::vector
に様々な方法で配列をpush_back
するサンプルコードを紹介します。
最も基本的な方法は、配列の要素を一つずつpush_back
する方法です。
#include <iostream>
#include <vector>
int main() {
int myArray[] = {1, 2, 3, 4, 5};
int arraySize = sizeof(myArray) / sizeof(myArray[0]);
std::vector<int> numbers;
// 配列の要素を一つずつpush_back
for (int i = 0; i < arraySize; ++i) {
numbers.push_back(myArray[i]);
}
// vectorの内容を表示
std::cout << "要素を一つずつpush_back:" << std::endl;
for (int number : numbers) {
std::cout << number << " ";
}
std::cout << std::endl; // 出力: 1 2 3 4 5
return 0;
}
この例では、for
ループを使って配列myArray
の各要素を順番にnumbers
というstd::vector
に追加しています。
std::vector
のコンストラクタに、配列の開始アドレスと終了アドレスを渡すことで、配列全体をコピーして初期化できます。
#include <iostream>
#include <vector>
int main() {
int myArray[] = {1, 2, 3, 4, 5};
int arraySize = sizeof(myArray) / sizeof(myArray[0]);
// コンストラクタに範囲を指定
std::vector<int> numbers(myArray, myArray + arraySize);
// vectorの内容を表示
std::cout << "コンストラクタで範囲指定:" << std::endl;
for (int number : numbers) {
std::cout << number << " ";
}
std::cout << std::endl; // 出力: 1 2 3 4 5
return 0;
}
この方法は、配列の要素を効率的にコピーしてstd::vector
を初期化するのに適しています。
insert
メソッドを使うと、std::vector
の任意の位置に配列の要素を挿入することができます。末尾に挿入する場合は、numbers.end()
を指定します。
#include <iostream>
#include <vector>
int main() {
int myArray[] = {1, 2, 3, 4, 5};
int arraySize = sizeof(myArray) / sizeof(myArray[0]);
std::vector<int> numbers;
// insertメソッドで範囲を指定
numbers.insert(numbers.end(), myArray, myArray + arraySize);
// vectorの内容を表示
std::cout << "insertメソッドで範囲指定:" << std::endl;
for (int number : numbers) {
std::cout << number << " ";
}
std::cout << std::endl; // 出力: 1 2 3 4 5
return 0;
}
insert
メソッドは、push_back
よりも汎用性が高く、std::vector
の任意の位置に要素を挿入できるのが利点です。
std::vector
がポインタを格納するように定義されている場合、配列の先頭アドレス(ポインタ)をpush_back
することができます。
#include <iostream>
#include <vector>
int main() {
int myArray[] = {1, 2, 3, 4, 5};
std::vector<int*> pointers;
// 配列の先頭アドレスをpush_back
pointers.push_back(myArray);
// vectorの内容を表示 (ポインタを通してアクセス)
std::cout << "配列へのポインタをpush_back:" << std::endl;
for (int* ptr : pointers) {
for(int i = 0; i < 5; ++i){
std::cout << ptr[i] << " ";
}
}
std::cout << std::endl; // 出力: 1 2 3 4 5
return 0;
}
この方法は、配列のコピーを作成せずに、元の配列を参照したい場合に有効です。ただし、元の配列の寿命がstd::vector
よりも短いと、不正なメモリにアクセスする危険性があるため注意が必要です。
C++11以降では、std::array
という固定長配列のテンプレートクラスが提供されています。std::array
は、従来のCスタイルの配列よりも安全で、std::vector
との相性も良いです。
#include <iostream>
#include <vector>
#include <array>
int main() {
std::array<int, 5> myArray = {1, 2, 3, 4, 5};
std::vector<int> numbers;
// std::arrayの要素を一つずつpush_back
for (int i = 0; i < myArray.size(); ++i) {
numbers.push_back(myArray[i]);
}
// vectorの内容を表示
std::cout << "std::arrayの要素をpush_back:" << std::endl;
for (int number : numbers) {
std::cout << number << " ";
}
std::cout << std::endl; // 出力: 1 2 3 4 5
return 0;
}
std::array
を使用すると、配列のサイズをコンパイル時に指定できるため、実行時のエラーを減らすことができます。
これらのサンプルコードを参考に、std::vector
に配列をpush_back
する方法を理解し、自分のプログラムに最適な方法を選択してください。
std::vector
に要素を追加する方法として、push_back
の他にemplace_back
というメソッドがあります。emplace_back
は、C++11で導入されたメソッドで、特にオブジェクトをvector
に追加する際のパフォーマンスに優れている場合があります。ここでは、push_back
とemplace_back
のパフォーマンスについて比較し、どのような場合にemplace_back
を使うべきかを考察します。
push_back
は、渡された引数から要素のコピーまたはムーブを行い、vector
の末尾に追加します。つまり、要素が既に存在する場合、コピーコンストラクタまたはムーブコンストラクタが呼び出されます。
#include <iostream>
#include <vector>
struct MyObject {
int value;
MyObject(int v) : value(v) {
std::cout << "コンストラクタ" << std::endl;
}
MyObject(const MyObject& other) : value(other.value) {
std::cout << "コピーコンストラクタ" << std::endl;
}
MyObject(MyObject&& other) : value(other.value) {
std::cout << "ムーブコンストラクタ" << std::endl;
}
};
int main() {
std::vector<MyObject> objects;
MyObject obj(10); // コンストラクタ呼び出し
objects.push_back(obj); // コピーコンストラクタ呼び出し
return 0;
}
この例では、push_back
によってMyObject
のコピーコンストラクタが呼び出されています。
emplace_back
は、vector
の末尾に直接オブジェクトを構築します。つまり、コンストラクタに渡す引数を直接指定することで、コピーやムーブ操作を省略できます。
#include <iostream>
#include <vector>
struct MyObject {
int value;
MyObject(int v) : value(v) {
std::cout << "コンストラクタ" << std::endl;
}
MyObject(const MyObject& other) : value(other.value) {
std::cout << "コピーコンストラクタ" << std::endl;
}
MyObject(MyObject&& other) : value(other.value) {
std::cout << "ムーブコンストラクタ" << std::endl;
}
};
int main() {
std::vector<MyObject> objects;
objects.emplace_back(10); // コンストラクタ呼び出し
return 0;
}
この例では、emplace_back
によって直接MyObject
が構築されるため、コピーコンストラクタやムーブコンストラクタは呼び出されません。
emplace_back
は、コピーやムーブ操作を省略できるため、以下の状況でpush_back
よりもパフォーマンスが向上する可能性があります。
- 複雑なオブジェクトの場合: コピーコンストラクタやムーブコンストラクタのコストが高いオブジェクトの場合。
-
一時オブジェクトの場合:
push_back
に一時オブジェクトを渡す場合、ムーブコンストラクタが呼び出されますが、emplace_back
ではオブジェクトを直接構築するため、ムーブ操作を省略できます。
ただし、emplace_back
は必ずしもpush_back
よりも高速であるとは限りません。単純な型の要素(int
やdouble
など)の場合、コピーコストが低いため、パフォーマンスの差はほとんどありません。
-
単純な型の要素の場合:
push_back
でもemplace_back
でもパフォーマンスに大きな差はないため、どちらを使っても構いません。可読性を重視して、push_back
を選ぶこともできます。 -
複雑なオブジェクトの場合:
emplace_back
を使うことで、コピーやムーブ操作を省略できる可能性があるため、パフォーマンスが向上する可能性があります。 -
一時オブジェクトの場合:
emplace_back
を使うことで、ムーブ操作を省略できるため、パフォーマンスが向上する可能性があります。
原則として、オブジェクトをvector
に追加する場合は、emplace_back
を優先的に検討することをお勧めします。 ただし、パフォーマンスが重要な箇所では、実際に両方のメソッドを試してみて、パフォーマンスを比較することが重要です。
emplace_back
は、std::vector
に要素を追加する際のパフォーマンスを向上させる可能性があるメソッドです。特に、複雑なオブジェクトや一時オブジェクトをvector
に追加する場合には、emplace_back
を使うことでコピーやムーブ操作を省略し、パフォーマンスを最適化することができます。パフォーマンスが重要な箇所では、push_back
とemplace_back
の両方を試してみて、最適な方法を選択してください。
C++で多次元配列を扱う場合、std::vector
を入れ子にして表現することが一般的です。この記事では、std::vector
を使って表現された多次元配列にpush_back
する方法について解説します。
最も一般的な多次元配列の表現方法は、std::vector
の中にstd::vector
を格納する「vector of vectors」です。
#include <iostream>
#include <vector>
int main() {
// 二次元配列 (vector of vectors) の宣言
std::vector<std::vector<int>> matrix;
// 行を追加
matrix.push_back({1, 2, 3}); // 1行目
matrix.push_back({4, 5, 6}); // 2行目
matrix.push_back({7, 8, 9}); // 3行目
// 要素へのアクセス
std::cout << matrix[0][0] << std::endl; // 出力: 1
std::cout << matrix[1][2] << std::endl; // 出力: 6
// 行を追加する別の方法 (push_backをネスト)
std::vector<int> row = {10, 11, 12};
matrix.push_back(row);
// 出力
for(const auto& row : matrix){
for(int val : row){
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
この例では、std::vector<std::vector<int>>
型のmatrix
という二次元配列を宣言しています。push_back
を使って、std::vector<int>
型の行をmatrix
に追加しています。
std::vector
を使うと、各行の要素数を可変にすることができます。
#include <iostream>
#include <vector>
int main() {
// 可変長の行を持つ二次元配列
std::vector<std::vector<int>> matrix;
// 1行目は2つの要素を持つ
matrix.push_back({1, 2});
// 2行目は3つの要素を持つ
matrix.push_back({3, 4, 5});
// 3行目は1つの要素を持つ
matrix.push_back({6});
// 出力
for(const auto& row : matrix){
for(int val : row){
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
この例では、各行の要素数が異なる二次元配列をstd::vector
を使って表現しています。
std::vector
を入れ子にすることで、3次元以上の多次元配列も表現できます。
#include <iostream>
#include <vector>
int main() {
// 3次元配列
std::vector<std::vector<std::vector<int>>> cube;
// 面を追加 (2次元配列)
cube.push_back({ {1, 2}, {3, 4} });
cube.push_back({ {5, 6}, {7, 8} });
// 要素へのアクセス
std::cout << cube[0][0][0] << std::endl; // 出力: 1
std::cout << cube[1][1][1] << std::endl; // 出力: 8
return 0;
}
この例では、std::vector<std::vector<std::vector<int>>>
型のcube
という3次元配列を宣言しています。push_back
を使って、二次元配列(面)をcube
に追加しています。
多次元配列の場合も、要素のコピーを避けるためにemplace_back
を使うことができます。
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> matrix;
//emplace_backを使って初期化
matrix.emplace_back(std::initializer_list<int>{1,2,3});
matrix.emplace_back(std::initializer_list<int>{4,5,6});
for(const auto& row : matrix){
for(int val : row){
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
- 多次元配列の場合、
push_back
を繰り返すことで、メモリの再割り当てが頻繁に発生し、パフォーマンスが低下する可能性があります。事前にサイズがわかっている場合は、reserve
メソッドを使ってメモリを確保しておくと、パフォーマンスを改善することができます。 - 多次元配列の場合、添字の範囲外アクセスに注意する必要があります。
at
メソッドを使うと、範囲外アクセスを検出することができます。
std::vector
を使うことで、C++で多次元配列を柔軟に扱うことができます。push_back
を使って要素を追加する際には、パフォーマンスやメモリ管理に注意し、必要に応じてemplace_back
やreserve
メソッドを活用してください。
std::vector
は、組み込み型だけでなく、構造体やクラスのオブジェクトも格納できます。ここでは、構造体やクラスの配列をpush_back
で扱う応用例について解説します。
構造体は、複数の異なる型の変数をまとめたものです。std::vector
を使って、構造体の配列を動的に管理できます。
#include <iostream>
#include <vector>
// 構造体の定義
struct Point {
int x;
int y;
};
int main() {
// Point型のvectorを宣言
std::vector<Point> points;
// Point型のオブジェクトをpush_back
Point p1 = {10, 20};
points.push_back(p1);
// 別の方法:emplace_backで直接構築
points.emplace_back(30, 40);
// 要素へのアクセス
std::cout << "Point 1: x = " << points[0].x << ", y = " << points[0].y << std::endl;
std::cout << "Point 2: x = " << points[1].x << ", y = " << points[1].y << std::endl;
return 0;
}
この例では、Point
という構造体を定義し、std::vector<Point>
型のpoints
という配列に、push_back
とemplace_back
を使ってPoint
型のオブジェクトを追加しています。
クラスは、構造体と同様に、複数のメンバ変数とメンバ関数を持つことができます。std::vector
を使って、クラスのオブジェクトの配列を動的に管理できます。
#include <iostream>
#include <vector>
// クラスの定義
class Rectangle {
public:
int width;
int height;
Rectangle(int w, int h) : width(w), height(h) {}
int area() const { return width * height; }
};
int main() {
// Rectangle型のvectorを宣言
std::vector<Rectangle> rectangles;
// Rectangle型のオブジェクトをpush_back
Rectangle r1(10, 20);
rectangles.push_back(r1);
// 別の方法:emplace_backで直接構築
rectangles.emplace_back(30, 40);
// 要素へのアクセスとメンバ関数の呼び出し
std::cout << "Rectangle 1 area: " << rectangles[0].area() << std::endl;
std::cout << "Rectangle 2 area: " << rectangles[1].area() << std::endl;
return 0;
}
この例では、Rectangle
というクラスを定義し、std::vector<Rectangle>
型のrectangles
という配列に、push_back
とemplace_back
を使ってRectangle
型のオブジェクトを追加しています。
構造体やクラスのオブジェクトが大きく、コピーコストが高い場合は、ポインタを使って配列を管理することができます。
#include <iostream>
#include <vector>
// クラスの定義 (再利用)
class Rectangle {
public:
int width;
int height;
Rectangle(int w, int h) : width(w), height(h) {}
int area() const { return width * height; }
};
int main() {
// Rectangle型のポインタのvectorを宣言
std::vector<Rectangle*> rectangles;
// Rectangle型のオブジェクトをnewで動的に生成
Rectangle* r1 = new Rectangle(10, 20);
rectangles.push_back(r1);
Rectangle* r2 = new Rectangle(30, 40);
rectangles.push_back(r2);
// 要素へのアクセスとメンバ関数の呼び出し (ポインタ経由)
std::cout << "Rectangle 1 area: " << rectangles[0]->area() << std::endl;
std::cout << "Rectangle 2 area: " << rectangles[1]->area() << std::endl;
// メモリの解放 (重要!)
delete r1;
delete r2;
rectangles.clear(); // vectorから要素を削除
return 0;
}
この例では、std::vector<Rectangle*>
型のrectangles
という配列に、Rectangle
型のオブジェクトへのポインタを追加しています。
注意点:
- ポインタを使って配列を管理する場合、メモリリークが発生しないように、必ず
delete
を使ってメモリを解放する必要があります。 - スマートポインタ (
std::unique_ptr
,std::shared_ptr
) を使うと、メモリ管理をより安全に行うことができます。
スマートポインタを使用すると、動的に割り当てられたメモリの自動的な管理が可能になり、メモリリークのリスクを減らすことができます。
#include <iostream>
#include <vector>
#include <memory> // スマートポインタを使うために必要
// クラスの定義 (再利用)
class Rectangle {
public:
int width;
int height;
Rectangle(int w, int h) : width(w), height(h) {}
int area() const { return width * height; }
};
int main() {
// Rectangle型のstd::unique_ptrのvectorを宣言
std::vector<std::unique_ptr<Rectangle>> rectangles;
// Rectangle型のオブジェクトをstd::make_uniqueで生成
rectangles.push_back(std::make_unique<Rectangle>(10, 20));
rectangles.push_back(std::make_unique<Rectangle>(30, 40));
// 要素へのアクセスとメンバ関数の呼び出し (ポインタ経由)
std::cout << "Rectangle 1 area: " << rectangles[0]->area() << std::endl;
std::cout << "Rectangle 2 area: " << rectangles[1]->area() << std::endl;
// メモリの解放は不要 (std::unique_ptrが自動的に行う)
return 0;
}
std::unique_ptr
は、所有権を共有しないスマートポインタで、オブジェクトが破棄される際に自動的にメモリを解放します。
std::vector
は、構造体やクラスの配列を動的に管理するのに非常に便利なツールです。push_back
やemplace_back
を使って要素を追加したり、ポインタやスマートポインタを使ってメモリ管理を効率化したりすることで、より柔軟で安全なプログラムを構築することができます。
この記事では、C++のstd::vector
におけるpush_back
メソッドを中心に、配列を柔軟に操作する方法について解説しました。
-
push_back
の基本:std::vector
の末尾に要素を追加するための基本的なメソッドであり、動的配列の柔軟性を最大限に活かすことができます。 -
配列を
push_back
する際の注意点: 型の不一致、配列全体のコピー、ポインタの扱いなど、注意すべき点を理解することで、安全かつ効率的なコードを作成できます。 -
emplace_back
との比較: オブジェクトの構築時にコピーやムーブを省略できるemplace_back
メソッドは、パフォーマンス向上のために有効な選択肢となります。 -
多次元配列の
push_back
:std::vector
を入れ子にすることで、柔軟な多次元配列を構築し、push_back
を使って動的に要素を追加できます。 -
構造体やクラスの配列を扱う: 構造体やクラスのオブジェクトを
std::vector
に格納することで、複雑なデータ構造を効率的に管理できます。スマートポインタとの組み合わせは、メモリリークを防ぐために非常に有効です。
std::vector
とpush_back
を組み合わせることで、C++プログラミングにおける配列操作は、より柔軟で効率的になります。静的なサイズの配列では実現できない、動的なサイズ調整や要素の追加・削除を容易に行うことができるため、データ構造の設計において非常に強力なツールとなります。
今回学んだ知識を活かし、push_back
を適切に活用することで、メモリ効率の良い、パフォーマンスの高い、そして何よりも柔軟なプログラムを開発していきましょう。std::vector
の機能を最大限に引き出し、C++でのプログラミングスキルをさらに向上させてください。