はかせのラボ

私の頭の中を書いていく雑記ブログです

C++ std::vectorのポインタから特定インデックスの要素を取り出す5つの方法

あいさつ

どうも、はかせです。

今日は以前上げたボーンの理屈に従って
カタカタコード打っていました。

その中でstd::vectorをポインタで渡して
渡した先で特定インデックスの要素を
参照するみたいなコードを書いてました。
(良いかは知らん。ただ個人的に配列の直渡しには苦い思い出がある)

その時に少し普段と違う書き方をする必要があり、
少し戸惑いました。

なのでその普段と少し違う書き方を
全部で5つ紹介します。

前提

まずここから話す内容はこんな感じの
メソッドの中での話となります。

struct PMD_BONE;//ボーン情報を定義した構造体
void BoneAnimation::Init(std::vector<PMD_BONE>* bones)
{
//ここから話していく内容
}

ボーン情報を配列に格納し
それをポインタで渡しています。

①一旦実体を別で格納し使う

まずは極めて単純な方法からです。
std::vectorには[]演算子オーバーロードが定義されており
この定義のおかげで通常の配列同様にインデックスによる
アクセスが可能になっております。

ですがわたってきているのはあくまでポインタなので
このオーバーロードが効きません。

なので一旦実体を取り出しこのオーバーロードを使えるようにしてやります。

auto boneVector = *bones;
auto value = boneVector[0];

良い点
・通常の配列操作と見た目同じなので理解しやすい

悪い点
・わざわざポインタで渡している意味が薄れる

②()と[]の合わせ技

これは私がメソッドチェーンだったりで
処理を一行で書くことが好きだから見つけただけです。
やることは上の①を一行にまとめます。

auto value = (*bones)[0];
auto value = *bones[0];//これはダメ

わざわざ一つローカル変数を持つこともなく
要素を取得できます。

ちなみに下の書き方だとおそらくですが、
bones[0]の実体を取ろうとしてできないから
エラーになるんだと思ってます。

良い点
・一行で書ける
・変なローカル変数がなくなる

悪い点
・ちょっとごちゃごちゃした印象になる

③0番地を使う

これは色々がちゃがちゃやって初めて知ったことなんですが、
bones[0] == *bones
みたいです。
(うまく言葉にできないからこれで察してくださいorz)

なのでさっきの②の一行書きはこんな感じで書き直せます。

auto value = bones[0][0];

良い点
・スッキリ一行で書ける

悪い点
・見た目が二次元配列なので変な勘違いを生みそう

④std::vectorのatを使う

これは単純にstd::vectorのメソッドを使ってやるだけです。
std::vectorのメソッドなんでポインタだろうが実体だろうが関係なく使えます。
cpprefjp.github.io

使い方はこんな感じ

auto value = bones->at(0);

良い点
・メソッドを使うためポインタだろうが関係なく一行で書ける
イテレーター等を使った場合と違い境界チェックと例外機構があるため安全

悪い点
・atメソッドを知らないとやってることがわからない
・境界チェックがある分少し遅い?でかい配列扱うと死ねそう

イテレーターを使う

これは割と配列ポインタを扱う際の
定番みたいなやりかたですね。

先頭アドレス+オフセットで
直接該当要素へジャンプします。

auto value = *(bones.begin() + 0);

良い点
・CやC++やってる人なら馴染みがあるためわかりやすい

悪い点
・強いて言うなら他言語から来たばっかりの人は分かりづらい程度?

あとがき

今回はstd::vectorのポインタから
特定インデックスの要素を取り出す5つの方法でした。

ちなみに採用されたのは④のstd::vectorのatを使うです。

理由としてはそんなでかい配列を扱う予定はないし、
(要素数はせいぜい数百程度)
それならより安全な方使うよねって感じです。

そして今回なぜstd::vector本体ではなく
ポインタにして受け取ってるかって言うと
std::vectorの参照を持っておきたいからですね。

ボーン情報は既にローダーの方で
ロードしたデータをstd::vectorで持っています。

それをわざわざ別もので持つのはバカらしいので
それに対する参照を持つことで解決しようとしたって感じです。

あとは素直に配列の直渡しっていい印象がない。
(内部的に全コピーが走ったりとかね)

そんなこんなでstd::vectorのポインタを扱うっていう
そこそこ奇妙な状態になったわけでした。

今回の記事が良ければスターやコメント等よろしくお願いします。
それでは今回はこの辺でノシ