はかせのラボ

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

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のポインタを扱うっていう
そこそこ奇妙な状態になったわけでした。

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

まとめ IL勉強の軌跡をまとめておく

あいさつ

どうも、はかせです。

このブログもなんやかんやいって1年強やってきました。

そうすると色んな記事が出てくるわけで
後から見ると自分でもどこになにがあるかわかりにくくなっている状況です。

なのでこれからちょくちょく時間を見つけて
過去記事のまとめや必要に応じてリライトなんかもしていきたいと思います。
(まぁそうそう時間ないんで頻度は低いでしょうが)

今回は割と最近やった
C#のIL記事をまとめていきます。

ILとは

hakase0274.hatenablog.com
ざっくり言うとC#機械語に直すために
一旦変換する言語です。

よく外国語勉強するときにやる奴ですよ。
ドイツ語→英語→日本語とか
フランス語→英語→日本語とか
(もしかしてこれやるの私ぐらい・・・?)

DnSpy

C#がどういうILに変換されるかを調べる
.NETデコンパイラってのがあるんですけど
その中の一つです。

これはそのなかでも特に高機能で色んな事が
これ一つでできます。

ただ高機能な分動作は少しもっさりしてますし、
逐一変更したら解放しなきゃいけないなど
イテレーション速度は若干遅めです。

私はぶっちゃけ数打ちまくって勉強する性質なので
すこし勉強用ツールとしては合わなかったかなぁと
今となっては思います。

後半はほとんどLINQPad+ILSpyでしたしね。
hakase0274.hatenablog.com

IL手書き

ILはC#が変換された言語なわけですが、
C#上でどういうILを吐くかってのを組み込むことができます。

というかIL書きってのは総じて
吐くILをC#コードに埋め込むことを言ったりします。
hakase0274.hatenablog.com

DynamicMethod

最強 of 最強
C#やILに存在する言語のルールを
超越するただ一つの存在です。
hakase0274.hatenablog.com

ループ

ILってのは≒アセンブラなんで
forだとかifだとか気の利いた構文は存在しません。

そういったことは全てgoto文で実現します。
ぶっちゃけ私はここが一番苦戦しましたね。
(ループではなくメソッドの種類にですが)
hakase0274.hatenablog.com

拡張メソッド

IL書きってのはVSとかのコード補完の恩恵を授かれません。
なので間違った書き方をしても誰も教えてくれません。
ただ動かないだけです。

それをちまちま一つずつ撲滅していくわけですが
その総数をできるだけ減らすためにも
こういった拡張メソッドを用意しておいて
少しでもIDEの恩恵を受けれるようにしておくことが吉だと思います。
hakase0274.hatenablog.com

命令の種類

同じような命令ってどの言語にもありますよね。
似てるんでわかりにくいですけど
そこには確かに意味があります。

その意味を知ったうえで使うのと知らないで使うのとでは
結構差があると思いますよ。
hakase0274.hatenablog.com

自動メモ化

私が上げてきたIL記事の中で一番反響があった記事ですね。
この記事は今までのILの知識を総動員して作ったものになります。

結果としては4.5秒の処理を
1ミリ秒まで高速化することに成功しております。
hakase0274.hatenablog.com

コンストラク

ILではというよりこれはC#のAssemblyBuilderの特徴ですが、
コンストラクタは他のメソッドとは少し扱いが違います。

なので継承とか使いだすとちょっとハマるかもしれませんね。
hakase0274.hatenablog.com

デストラク

こいつもこいつで少し扱いが特殊です。
というのもデストラクタというメソッドを
取得するのが少し手間なんですよね。
ただ一度できてしまえばあとはそんな苦労しないと思います。
hakase0274.hatenablog.com

あとがき

今回はIL記事のまとめでした。
一個一個振り返りながらコメントとかもつけてみましたが
いかがでしたでしょうか。

ここに上げた記事を一通り見て
それとなく手元で動かしてもらったら
ILってのがなんなのか
どう使うのか
どう難しいのかってのが
なんとなーくわかってもらえるんじゃないかなぁと思っております。
(さすがに自画自賛しすぎ?)

ILに限らずですが
世間一般で難しいと言われているものは
大抵難しいのではなくめんどくさいだけです。

ILもそうですしDirectXもそうです。
普段C#とかUnityとかが内部でやってくれてることを
プログラマーが自分でやるだけのことです。

なのでそんなアレルギーみたく毛嫌いしないで
一回やってみてはいかがでしょうか?

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


一個一個順を踏んでやっていけば
誰でもできることです。