[C++]std::vectorとポインタのメンバアクセスの違いについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sereparu
記事: 17
登録日時: 8年前

[C++]std::vectorとポインタのメンバアクセスの違いについて

#1

投稿記事 by sereparu » 8年前

現在、Win32プロジェクトのゲームアプリを以下のような環境で制作しています。

 OS:Windows7(64bit) Home Premium SP1
 統合開発環境:Visual Studio Community 2017
 コンパイラ:Visual C++ 2017
 ライブラリ:DXライブラリVer3.18a

質問は、構造体を要素に持つ配列のメンバアクセスについてです。
構造体を要素に持つ配列を動的に確保するのにstd::vectorを使っていますが
ポインタを使った方が処理が速いということを聞き、ポインタを使った方が良いのかな、と考えています。

ですが、ポインタは上級者向けで難しいというイメージがあるのと、メンバアクセスは
アロー演算子を使わなければならないのが個人的に分かりづらいということもあり、使用を避けていました。

しかし、試しに下記のソースのようにポインタのメンバアクセスをアロー演算子を使わずに
std::vectorと同じような方法で記述してみたところ、問題なくアクセスできているように思えます。
(下記のソースを実行すると、test[0].a = 1、test[1].a = 2 と出力されます)

ポインタのメンバアクセスはvectorと同じ方法で問題ないのでしょうか?
また、問題がない場合、配列をstd::vectorで宣言している部分をポインタで宣言するように変更すれば
処理を高速化することができるのでしょうか?

C++初心者で、ポインタについての理解がまだほとんどないため、ご教授願います。
よろしくお願い致します。

コード:

#include "stdafx.h"
#include <iostream>
#include <vector>

// 構造体
struct Test {
	int a;
};

int main() {

	// 確保する要素数
	int num = 10;

	std::vector<Test> test;
	Test* testp;

	// メモリの動的確保
	test.resize(num);
	testp = new Test[num];

	// 構造体のメンバ「a」に値を代入
	test[0].a = 1;
	testp[1].a = 2;

	// メンバの値をコンソールに出力
	std::cout << "test[0].a = " << test[0].a << "\n";
	std::cout << "testp[1].a = " << testp[1].a << "\n";

	// 入力待ち
	getchar();

	// メモリの解放
	delete[] testp;
}

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: [C++]std::vectorとポインタのメンバアクセスの違いについて

#2

投稿記事 by usao » 8年前

>ポインタを使った方が処理が速いということを聞き

とかいう記述では,内容が非常にあやふやです.
その 聞いた話 をご自身で理解していて且つ重要な事柄だと思われているのであれば,
最初から「速い」とされている方法を取ればよいだけなのではないでしょうか.

そこらへんのインパクトを把握できていないのであれば,
実際に 動作速度が遅くて困った! となってから考えればよいのではないでしょうか.


文法的な事柄に関しては,文面を読むに,何か誤解がありそうに見えます.

「試しに書いてみた → 動いていそうだけど,果たして?」 とかいうやり方ではなく,
「文法を理解 → 書く」 という手順とすることをお勧めします.
書いた時点で,そのコードの意味(意図)は書いた人間には自明であるべきです.

sereparu
記事: 17
登録日時: 8年前

Re: [C++]std::vectorとポインタのメンバアクセスの違いについて

#3

投稿記事 by sereparu » 8年前

usaoさん
ご回答ありがとうございます。

内容があやふやな質問をしてしまい、申し訳ございません。
ポインタを使うことを考えたのは、制作中のゲームの動作速度が遅くて困っていたことが理由なので
ポインタを使うメリットについても「処理を高速化できる」というイメージしかないまま質問していました。
(ポインタはデータを格納しているアドレスを示すだけなので、データ自体を扱うより高速、というような簡単な理解しかできていません)

ゲームでは、画面上に表示させるキャラクターを構造体(座標、画像情報、ステータス等のメンバ変数を持つ)で定義しています。
一度に表示させるキャラクターの数が少ない場合は問題ないですが、1000体のように大量に表示させる場合は、処理落ちが発生してしまいます。
そこで、構造体の配列をstd::vectorからポインタを使うように作り直して、上記と同じ条件で大量のキャラクターを表示させたところ、処理落ちが発生せず、CPU使用率も半分以下になり、ポインタの方が速いという実感を感じたので、ポインタを使いたいという気持ちが湧きました。

ポインタの文法について調べて、ポインタを使った場合の構造体配列のメンバ変数の参照は

 (ポインタ名 + 要素番号)->メンバ変数名

のように書くところまでは理解しました。
ただ、これまでstd::vectorを使用してきたため、既に制作した処理では構造体配列のメンバ変数の参照を

 配列名[要素番号].メンバ変数名

というstd::vectorの書き方で進めてきました。

しかし、既に制作した処理の、構造体配列の宣言の部分とメモリの動的確保の部分だけを
std::vectorからポインタの書き方に変えて、メンバ変数へのアクセスの書き方はstd::vectorの書き方のままでも
今までと変わりなくゲームが問題なく動作しました。

上記のソースの例だと、「testp[1].a」と「(testp + 1)->a」は同じ値が返りました。

そのため、この2つの書き方は同じ意味なのか、それとも偶然同じ値が返っただけなのか、という疑問が出てきました。
2つの書き方の違いについて調べているのですが、違いが明確に記述されている情報が見つかりません。

以下のページでは、ポインタ変数で配列要素へアクセスする書き方について
「data[5]」と「*(data + 5)」は全く同じ意味という記述があるのですが、
構造体のメンバ変数へのアクセスについても同じことが言えるのでしょうか?
http://9cguide.appspot.com/15-07.html

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: [C++]std::vectorとポインタのメンバアクセスの違いについて

#4

投稿記事 by usao » 8年前

>「data[5]」と「*(data + 5)」は全く同じ意味という記述があるのですが、
>構造体のメンバ変数へのアクセスについても同じことが言えるのでしょうか?

少なくとも,あなたが示したコード例の testp に関してはそうです.

>testp = new Test[num];
によって,num(=10)個のTest型インスタンスが(配列的な並びで)生成され,
ポインタ testp は,その先頭インスタンスの場所を指しています.

「構造体でメンバがどうの」という言葉に惑わされてしまうようなら,
なじみの深いintで考えてみるとわかりやすいでしょう.

コード:

int Array[10];  //10個のint型インスタンス
int *p = Array;  //先頭を指す
としたときの p と同様です.


しかし,速度面の話はわかりません.

std::vector<Test> としていたのを
std::vector<Test*> という形にしたら,処理速度が向上した

というストーリーであれば想像も付くのですが,
示されたコード例のように,単に自前でnewする形に切り替えただけで
劇的に速度が向上した という話なのであれば,何がどうしてそうなったのか私には全く想像つきません.

sereparu
記事: 17
登録日時: 8年前

Re: [C++]std::vectorとポインタのメンバアクセスの違いについて

#5

投稿記事 by sereparu » 8年前

usaoさん
ご回答ありがとうございます。

色々確認してみましたが、問題がなさそうなので、このままポインタを使ってみようと思います。
速度面については、速くなった理由がはっきりとはしませんが、一応解決とさせていただきます。
ありがとうございました。

返信

“C言語何でも質問掲示板” へ戻る