もちろんC++ Builder CEでも使えますし、黙って使っていましたが、一度基礎から扱います
さて、vector(ベクターないしベクトル)は、
C++標準ライブラリ(<vector>)で提供される、サイズを動的に変更できる可変長配列のコンテナクラスです。生の配列とは異なり、要素の追加や削除に応じてメモリ領域が自動で管理されます。
添え字(index)で扱えるという意味では配列に似ています。ヘッダーをインクルードすると使えます。例を挙げましょう。
#include <iostream>
#include <vector>
int main() {
// ベクトルの宣言と初期化
std::vector<int> numbers;
// 末尾へ要素を追加する
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
// 要素数(size)の取得
std::cout << "要素数: " << numbers.size() << std::endl;
// 添字(インデックス)で要素にアクセス
std::cout << "1番目の要素: " << numbers[0] << std::endl;
// 範囲ベースfor文で全要素を走査
std::cout << "要素一覧: ";
for (int n : numbers) {
std::cout << n << " ";
}
std::cout << std::endl;
return 0;
}要素がintなvectorを宣言していますが、それなら配列を使えばいいので、ユーザが定義した型のインスタンスを入れるコンテナとしてvectorを使いましょう。さらにそれをソートします。
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
struct Person {
int id;
std::string name;
};
int main() {
std::vector<Person> people = {{2,"Bob"}, {1,"Alice"}, {3,"Charlie"}};
std::sort(people.begin(), people.end(), [](const Person &a, const Person &b){
return a.id < b.id; // idで昇順
});
for( int i = 0 ; i < people.size() ; i++ )
std::cout << people[i].id << " " << people[i].name << std::endl;
}struct Person {
int id;
std::string name;
};
Personというユーザ定義の型(構造体)です。これを宣言してさらに初期化(要素数は3)するコードが、
std::vector<Person> people = {{2,"Bob"}, {1,"Alice"}, {3,"Charlie"}};
です。
次でソートしていますが、ラムダ式([])が分かりにくいですね。ラムダ式は関数を”そこに”表現するC++の記法で、慣れれば別関数として書くより可読性が高くなります。
std::sort(people.begin(), people.end(), [](const Person &a, const Person &b){
return a.id < b.id; // idで昇順
});
降順ならば、
return a.id > b.id;
です。一度C++ Builder CEのc++ コンパイラで動かして見ましょう。
jakeb@Orbit-11 MINGW64 ~/Dropbox/vector-sort
$ cat main.cpp
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
struct Person {
int id;
std::string name;
};
int main() {
std::vector<Person> people = {{2,"Bob"}, {1,"Alice"}, {3,"Charlie"}};
std::sort(people.begin(), people.end(), [](const Person &a, const Person &b){
return a.id < b.id; // id
});
for( int i = 0 ; i < people.size() ; i++ )
std::cout << people[i].id << " " << people[i].name << std::endl;
}
jakeb@Orbit-11 MINGW64 ~/Dropbox/vector-sort
$ bcc32c main.cpp
Embarcadero C++ 7.70 for Win32 Copyright (c) 2012-2024 Embarcadero Technologies, Inc.
main.cpp:
Turbo Incremental Link 6.99 Copyright (c) 1997-2024 Embarcadero Technologies, Inc.
jakeb@Orbit-11 MINGW64 ~/Dropbox/vector-sort
$ ./main
1 Alice
2 Bob
3 Charlie
vectorの全要素を表示するループは、
for( int i = 0 ; i < people.size() ; i++ )
std::cout << people[i].id << " " << people[i].name << std::endl;
people.size()は要素数を返します。従って先頭要素から最終要素までをダンプするコードは上のようになります。people[i]で各要素がアクセスできていることが理解できます。んでも、構造体の配列でも同じですね。vectorの場合は、”イテレータ”というものが使えます。無理矢理日本語にすると”反復子”あるいは”繰り返し子”ですかね。おおよそvectorの各要素へのポインタだと思って間違いはないです。これを使うと、
for( auto it = people.begin() ; it != people.end() ; it++ )
std::cout << it->id << " " << it->name << std::endl;
型の推定を使いました。のでauto itでイテレータを宣言しています。先出ししてしまいましたが、実はpeople.begin()とかpeople.end()はイテレータを返していました。ついでにも一つ、範囲for文を使うと、もう少し簡潔に書けます。
for (データ型 変数名 : コンテナ)
{
// 処理
}
が基本なので、上の例に当てはめると、
$ cat main-ranged-for.cpp
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
struct Person {
int id;
std::string name;
};
int main() {
std::vector<Person> people = {{2,"Bob"}, {1,"Alice"}, {3,"Charlie"}};
std::sort(people.begin(), people.end(), [](const Person &a, const Person &b){
return a.id < b.id;
});
for( const auto& it : people )
std::cout << it.id << " " << it.name << std::endl;
}
jakeb@Orbit-11 MINGW64 ~/Dropbox/vector-sort
$ bcc32c main-ranged-for.cpp
Embarcadero C++ 7.70 for Win32 Copyright (c) 2012-2024 Embarcadero Technologies, Inc.
main-ranged-for.cpp:
Turbo Incremental Link 6.99 Copyright (c) 1997-2024 Embarcadero Technologies, Inc.
jakeb@Orbit-11 MINGW64 ~/Dropbox/vector-sort
$ ./main-ranged-for
1 Alice
2 Bob
3 Charlie
宣言と初期化で要素を追加するのでなく、1要素が得られたら都度vectorに追加していく具体的な例は、次の記事で述べる予定です。C++にはvector以外にも入れ物(コンテナクラス)として、arrayとかqueueとか種々あります。


コメント