質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

8回答

22841閲覧

c++では配列[]はあまり使わないものなんですか?

teraterm

総合スコア12

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

1グッド

1クリップ

投稿2018/05/18 13:03

C/C++初心者ですが、仕事でC++の中規模開発に携わることになりました。今までJavaで開発していたのですが、Javaでの開発は要素数が事前にわかっていれば極力配列を使えと教えられてきましたが、C++では配列を扱うのはstd::vectorがメインのように感じます。処理が簡潔になるのはよくわかるのですが、配列を使ってもっとレガシーな感じで書きたいのですが実際の現場ではどう使われているのか、皆様のご意見をお聞かせ頂きたく投稿させていただきました。

keicha_hrs👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

LouiS0616

2018/05/18 13:28

『Javaでは生配列を使うべきだと教えられた根拠』が気になるところです。
teraterm

2018/05/18 13:55

Javaでは生配列を使うべきだとは教えられていないです。
guest

回答8

0

c++では配列[]はあまり使わないものなんですか?

(私個人の希望的予測も含めて)はい。

配列要素数がある程度少なく、恒久的に要素数が変化しないと確信できるケースを除いて、生の配列型よりも std::vector<T>std::array<T,N> クラスの利用を推奨します。

Java言語とC++言語の大きな違いとして、Javaの配列型はそれ自身が要素数(length)を管理しているが、C++の配列型の要素数はプログラマの責任で別途管理する必要があります。C++配列型の利用はプログラマの責任範囲が大きく、典型的なバグの温床になっています。

Java

1void method(int[] arr) { 2 int len = arr.length; // 配列arr自身が要素数を知っている 3}

C++

1void method(int arr[], size_t n) { 2 // 配列arrとは別に要素数nをセットで管理する必要がある 3 // 実際の要素数とあわせて管理しないと致命的なバグを引き起こす 4} 5 6void method(std::vector<int>& v) { 7 size_t n = n.size(); // vector型自身は要素数を知っている 8} 9 10void method(std::array<int, 10>& v) { 11 size_t n = n.size(); // array型自身は要素数を知っている(n==10) 12}

投稿2018/05/18 13:42

編集2018/05/18 13:45
yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teraterm

2018/05/18 13:51

要素数の問題は大きいですね
guest

0

各言語の配列またはリストを集めました。レガシーな実装、抽象クラス、ソート済みリスト、キューやスタック、多次元配列や行列は除外しています。

実装の「固定長配列」は確保されたメモリ領域が作成時のサイズ固定で変更されないこと、「可変長配列」は確保されたメモリ領域が作成時のサイズ固定ではなく、領域の拡張や縮小が出来るというと言うこと。ただし、拡張時に連続したメモリ領域を取れない場合は別の領域を新たに確保するようなreallocのような動作を想定しています。


Java

種類サイズサイズ取得要素の型実装
配列 T[]実行時固定lengthプリミティブ型と参照型固定長配列
java.util.ArrayList可変size()参照型可変長配列
java.util.LinkedList可変size()参照型双方向リスト
java.util.concurrent.CopyOnWriteArrayList可変size()参照型COW配列?

CopyOnWriteArrayListはスレッドセーフなArrayListの実装ですが、どうから、Copy-On-Write(COW)の仕組みで要素を管理しているらしいです。詳しいところはソースコードまで確認していないので、ちょっとわからないのですが。

C

種類サイズサイズ取得要素の型実装
配列 T[]コンパイル時固定sizeof全て固定長配列
可変長配列(VLA)コンパイル時固定sizeof全て固定長配列
動的メモリ確保(malloc等)可変全て可変長配列

sizeofは配列の要素数ではなく、領域のサイズになりますので、要素数を求めるには型のサイズで割る必要があります。

Visual C++のように可変長配列(VLA)を実装していないコンパイラもあります。なお、この可変とはコンパイル時に対して可変という意味で、配列作成後に可変という意味ではありません。

動的メモリ確保は配列を作るのでは無く、メモリ領域を確保するだけになります。確保したメモリ領域を配列と同じようにアクセスできると言うだけに過ぎません。

C++

種類サイズサイズ取得要素の型実装
配列 T[]コンパイル時固定sizeof全て固定長配列
動的メモリ確保(malloc等)可変全て可変長配列
std::arrayコンパイル時固定size全て固定長配列
std::vector可変size全て可変長配列
std::foward_list可変size全て片方向リスト
std::list可変size全て双方向リスト

C++には可変長配列(VLA)がありません。

C#

種類サイズサイズ取得要素の型実装
配列 T[]実行時固定?Length全て固定長配列?
System.Collections.Generic.List可変Count全て可変長配列
System.Collections.Generic.LinkedList可変Count全て双方向リスト

C#ではArray.Resize()で配列のサイズを変更可能のように見えます。しかし、配列は参照型であるにもかかわらず、Array.Resize()では参照渡し(ref付き)でなくてはならない所から、配列自体を変えると言うより変数を置き換えるという動作のようです。

C#

1public class Test 2{ 3 public static void Main() 4 { 5 int[] x = {0, 1, 2, 3}; 6 System.Console.WriteLine(x.Length); // => 4 7 System.Array.Resize(ref x, 5); 8 System.Console.WriteLine(x.Length); // => 5 9 OtherResize6(x); 10 System.Console.WriteLine(x.Length); // => 5 のまま 11 System.Console.WriteLine(x[0]); // => 10 変更されている。 12 System.Console.WriteLine(x[1]); // => 1 変更されていない。 13 } 14 public static void OtherResize6(int[] a) 15 { 16 a[0] = 10; 17 System.Array.Resize(ref a, 6); 18 a[1] = 20; 19 } 20}

配列は参照型ですので、通常は共有渡しになります。上記のように共有渡ししたあとにArray.Resize()をしても、元々のオブジェクトには影響を与えていません。その後の要素変更も反映されなくなっています。

私もよくわからないので、あとはC#に詳しい人に聞いてください。


さて、同じ配列と言っても、各言語によってその性質は微妙に異なる物です。同じ固定長であっても、コンパイル時固定と実行時固定は出来ることに大きな違いがあります。実行時固定は新たな配列を作り直してコピーすることで可変な配列のように扱えないわけではありません。C#のArray.Resize()がまさしくそのような動作です。しかし、コンパイル時固定の場合、入力などによってサイズが変わるようなデータを扱うことはほぼ不可能です。つまり、Javaの配列で出来ることがそのままC++の配列でも出来るとは限らないと言うことです。

次に、Java特有の問題について書きましょう。JavaのArrayList等はint等のプリミティブ型を扱えません。普通の整数の可変長なりストを作りたい…と言う場合はArrayList<Integer>と言う風にラッパークラスを使うしか無いと言うことです。現在はオートボクシング機能があるため、以前よりは書きやすくなったとは言え、ラッパークラスの取り扱いは非常に面倒です。また、四則演算するだけでもプリミティブ型とラッパークラスの間に相互変換が入ります。ある程度はキャッシュしてくれるとは言え、オブジェクトが作成を繰り返すことになるため、少なくないコストがかかります。言ってしまえば、int[]ArrayList<Integer>では、無視できないぐらいのパフォーマンスの差があると言うことです(参照: java - Lists, primitive types, and performance - Stack Overflow)。

こういった側面を考えて、Javaではなるべく配列を使う(特にプリミティブ型では)というのはありだと思います。ただ、Java 8以降はintをそのままストリームにするIntStream等を(コードの内容によりますが)代替に使うのもありかと思います。

これに比べて、C++のstd::vectorは、どのような型でも扱えますし、内部の実体は通常の配列と同じようになっているため、パフォーマンスが急激に落ちると言った所がありません。むしろ、コンパイル時固定の配列は使用できるところが限られるという面もあります。だから、ほとんどの場合はstd::vectorを使用しているように思います。

なお、コンパイル時固定でも構わないという場合は、インタフェースの共通性からstd::arrayを使うことの方が多いような気がします。私の場合、配列特有の動作(コンストラクタとかデストラクタとか、配列に合わせた動きをするようにできています)が勉強不足で理解できていないから、近づかないように避けているだけって事情もありますが…。

投稿2018/05/18 23:18

raccy

総合スコア21739

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2018/05/19 00:19

大作、ご苦労様。ただ、ここまで考えて使える人って、ごく僅かな気がします。混在させてバグらないでくれってのが正直なところ。
teraterm

2018/05/19 01:21

言語間のサンプルわかりやすいです
guest

0

そもそも、C/C++言語においては'配列'というのは特例の塊みたいなもんなのです。

c++

1#include <iostream> 2using namespace std; 3void print1(int a[]){ cout << sizeof(a) << endl; } 4void print2(int a[4]){ cout << sizeof(a) << endl; } 5void print3(int a[0]){ cout << sizeof(a) << endl; } 6int main(){ 7 int a[4] = {0}; 8 cout << sizeof(a) << endl; // 16 9 print1(a); // => 8 10 print2(a); // => 8 11 print3(a); // => 8 12 cout << sizeof(int*) << endl; // => 8 13 // int b[4] = a; // コンパイルエラー 14}

これがSTLのarrayを用いることで

c++

1#include <iostream> 2#include <array> 3#include <vector> 4using namespace std; 5void print1(vector<int> a){ cout << a.size() << endl; } 6void print2(array<int, 4> a){ cout << a.size() << endl; } 7void print3(array<int, 0> a){ cout << a.size() << endl; } 8int main(){ 9 array<int, 4> a{4,3,2,0}; 10 cout << a.size() << endl; // 4 11 print1(vector<int>(begin(a), end(a))); // => 4 12 print2(a); // => 4 13 // print3(a); // コンパイルエラー 14 15 array<int, 4> b = a; 16 for(auto& i : b){ cout << i; } // => 4320 17}

と、大分直感的になります。
今後、C++においてはarrayの方を配列と呼ぶ事になると嬉しいという希望的推測
(ついでにvectorへの変換もうちょいスムーズになって欲しい)

投稿2018/05/18 23:02

編集2018/05/18 23:03
asm

総合スコア15149

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teraterm

2018/05/18 23:39

確かに直感的になりますね
guest

0

C++で配列[]

装置相手にする際、最大メモリサイズも決まっているのでよく使っています。
またH8でもC++使うことありますけど、vectorなどテンプレートライブラリを組み込むメモリなぞ余ってないので配列は使ってます。

投稿2018/05/18 21:24

YomogiKOBO

総合スコア187

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teraterm

2018/05/18 23:35

適材適所ですね
guest

0

こんにちは。

Javaでの開発は要素数が事前にわかっていれば極力配列を使えと教えられてきました

C++でも同じです。コンパイルする時までに要素数が判っているなら配列、もしくは、std::arrayを使うのが好ましいです。
Javaには詳しくないのですが、もしJavaの配列がC#の配列と同じようなものなら、C++ではstd::unique_ptr<T[]>がほぼ同等です。


ああ、yohhoyさんの回答をみて、要素数の管理のことを忘れていることに気が付きました。std::arrayなら要素数も管理してくれます。ややこしいけどstd::unique_ptr<std::array<T, N>>かな。

投稿2018/05/18 13:42

編集2018/05/18 13:44
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teraterm

2018/05/18 13:55

std::unique_ptr<std::array<T, N>>ですか、奥が深いですね
guest

0

ベストアンサー

すでに出そろっている感がありますが、私の場合もC++では素の配列を使うことは減りましたね。可変サイズにしたいときや大量のデータを扱うときはほぼvector<>ですし、固定サイズはarray<>が便利なのでそれを使います。

配列を使ってもっとレガシーな感じで書きたいのですが

それに何の意味があるのかよく判りません。意図せぬバグの温床となること請け合いです。素の配列はサイズの管理が煩雑になりがちですし、範囲チェックも設計者の責任で行わなければいけません。

ただし、素の配列が便利なケースもあります。例えば、テンプレートとの組み合わせで素の配列でもサイズ管理が可能な場合ですね。

c++

1template <size_t N> 2void function(int (&data)[N]) 3{ 4 std::cout << "N=" << N << std::endl; 5 for(auto x : data) 6 { 7 std::cout << x << std::endl; 8 } 9} 10 11int main() 12{ 13 int a[]{1, 2, 3}; 14 function(a); 15 int b[]{1, 2, 3, 4, 5, 6}; 16 function(b); 17 return 0; 18}

array<>では上記配列a,bのような初期化ができないので、そのような書き方をしたい場合は素の配列を使うことがあります。

投稿2018/05/19 00:33

catsforepaw

総合スコア5944

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teraterm

2018/05/19 01:36

テンプレートを使うと配列数が取れるんですね。こういうのを適宜使いたいと思います
catsforepaw

2018/05/19 02:32

raccyさん 情報ありがとうございます。見落としていました。 早速試してみたところエラーになるのでVC++ではまだ使えないのかと思いましたが、コンパイルオプションの言語の設定でC++言語標準をC++17にしたら使えるようになりました(このオプションの設定も見落としていました……)。 ただ、便利そうではありますが、型も推論で決めているので暗黙の型変換が効かず、各要素の型を厳密に合わせてやらないとエラーになるのが難点ですね。あと、その方法でshort配列などを作ろうとすると非常に面倒そうです。
yohhoy

2018/05/22 01:41 編集

FYI: C++17で導入された「クラステンプレートのテンプレート引数推論 」 https://cpprefjp.github.io/lang/cpp17/type_deduction_for_class_templates.html の恩恵ですね。ただcatsforepawさんが指摘するように"型は明示しつつ要素数は推論させる"とはできないので、利用シーンに合わせてといったところでしょうか。
guest

0

配列って、後から、変更できないとか、色々と不便だからではないでしょうか?
また、初期のCの頃だと、配列でのアクセスが効率良かった、という面もあると思いますが、今は、その程度の効率より、使いやすさが優先していると思っています。

あ、構造体とかの配列をポインタでアクセスすると、よく間違えるってものあった思います。
それらを含めて、配列が推奨されにくいのかも知れません。

投稿2018/05/18 13:11

pepperleaf

総合スコア6385

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teraterm

2018/05/18 13:18

ご回答ありがとうございます。 C++では配列は推奨されにくいのですね。 まだモヤモヤしています。
guest

0

解決済みですが数点

javaとかC++の流儀ということもありますが、結局は組織のルール(要するに上司の好み)で方針が変わると言うことはザラにあります。同じやり方なのに上司が変わっただけでダメになるなんて日常茶飯事です。

一方が他方の完全上位互換というわけでない以上、一長一短であり、好みでやり方が変わることは当然です。まあ、困ったらSTL使っておけばとりあえずは問題ないと思います。「固定長」であるという前提があったとしても、これが覆ることも多々ありえますし。ただし、デバッグ時の絞り込みが難しくなる欠点がありますので、これをどう考えるか次第だと思います。

もっとも、上司や取引相手と早い段階で仕様確定できればそれに越したことはありません。まあ、「こんなこと自分で考えろ」という人もいますけどね。どのみち「人次第」の要素が大きいですね。

投稿2018/05/19 07:10

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問