導入
C++のstd::vectorは非常に便利な動的配列ですが、既存のC言語で書かれたライブラリや、OSの低レイヤーAPIを呼び出す際に「配列の先頭ポインタが欲しい」という場面によく遭遇します。そんな時、std::vector::data() を活用すれば、安全かつ簡潔にポインタを取得し、レガシーなインターフェースとの橋渡しが可能です。
基礎知識
std::vectorは内部でメモリを動的に確保し、要素を連続したメモリ領域に格納しています。std::vector::data() は、その内部メモリ領域の先頭アドレスを直接指すポインタ(T)を返します。std::vectorは「連続したメモリ配置」が規格で保証されているため、data() メソッドを使うことで、C言語の配列と同じ感覚でメモリを扱うことができるのです。
実装/解決策
std::vector::data() を使用する最大のメリットは、型安全性を保ちつつ、高速にデータへアクセスできる点です。また、サイズが0の空のvectorに対してdata()を呼び出した場合、ヌルポインタか非ヌルポインタのいずれかが返されるため、呼び出し後に必ず有効なポインタであるかチェックする習慣をつけると、より堅牢なコードになります。
サンプルプログラム
以下のコードは、std::vectorで管理している数値を、C言語の関数(ここでは擬似的に引数でポインタとサイズを受け取る関数)に渡す例です。
include <iostream>
include <vector>
// C言語風のインターフェースを持つ関数を想定
void process_raw_array(const int data, size_t size) {
for (size_t i = 0; i < size; ++i) {
std::cout < data[i] < " ";
}
std::cout < std::endl;
}
int main() {
std::vector<int> vec = {10, 20, 30, 40, 50};
// vectorの内部ポインタを取得してC言語風関数に渡す
// data()を使うことで、配列の先頭アドレスを直接指定できる
if (vec.data() != nullptr) {
process_raw_array(vec.data(), vec.size());
}
return 0;
}
応用・注意点
注意が必要なケースとして、vectorの要素を追加(push_backなど)したり、メモリを再確保するような操作を行うと、内部でメモリの再配置(リバッファリング)が発生します。これにより、以前取得していたポインタは「無効(ダングリングポインタ)」になります。
ポインタを取得した後は、vectorのサイズを変更するような処理を行わないスコープ内で速やかに使い切るか、ポインタを保持し続けなければならない状況では注意深く設計を行うようにしましょう。また、const std::vectorを使うと、読み取り専用のポインタ(const T)が得られるため、APIの仕様に合わせて使い分けるのが現場の鉄則です。

コメント