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

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

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

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

Q&A

解決済

3回答

36986閲覧

構造体の初期化方法について(C++)

nomi

総合スコア32

C++

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

0グッド

3クリップ

投稿2018/01/29 17:00

質問

他人のコードを読んでいた時、構造体へ一度に初期化するコードを見かけました。それが以下のコードです。

C++

1#include <iostream> 2 3struct RGB { 4 int red, green, blue; 5}; 6 7int main() { 8 struct RGB cube1 = {1, 5, 6}; // 方法1 9 struct RGB cube2 = RGB{1, 5, 6}; // 方法2 10 11 return 0; 12}

そこで質問があります。構造体を初期化する際、{1, 5, 6}で初期化する方法と、RGB{1, 5, 6}で初期化する方法は、意味としては同じなのでしょうか?


cube1cube2のメンバを表示した結果、ちゃんと初期化されていることは確認しました。しかし、方法1と方法2では書き方が違うので、本当に方法1と方法2が同じ意味なのか気になったので質問しました。

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

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

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

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

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

guest

回答3

0

ベストアンサー

構造体を初期化する際、{1, 5, 6}で初期化する方法と、RGB{1, 5, 6}で初期化する方法は、意味としては同じなのでしょうか?

同じ意味です。


(細かい仕様のお話;通常は気にしなくても良いです)

C++

1struct RGB cube1 = {1, 5, 6}; // 方法1 2struct RGB cube2 = RGB{1, 5, 6}; // 方法2

C++言語の構文上はそれぞれ 1) 変数cube1のcopy-list-initialization、2) direct-list-initializationされた一時オブジェクトによる変数cube2の初期化になります。最新のC++仕様(C++17)では、1)/2)は同一の振る舞いになることが保証されます。過去バージョン(C++11~C++14)でも、実用上は1/2)の書き方で差異はありません。もっと古いバージョン(C++03以前)では、2)の書き方がコンパイルエラーになります。

投稿2018/01/30 02:26

yohhoy

総合スコア6191

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

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

nomi

2018/01/30 12:42

yohhoyさん、回答頂きありがとうございます。追加で質問なのですが、構造体を以下のコードのように扱いたいのですが、この場合も方法1と方法2は同じ意味なのでしょうか? ```C++ #include <iostream> #include <vector> struct RGB { int red, green, blue; }; int main() { std::vector<RGB> cubes; cubes.push_back({1, 5, 6}); // 方法1 cubes.push_back(RGB{1, 5, 6}); // 方法2 return 0; } ```
yohhoy

2018/01/30 16:28

同じ意味です。 (構文的には1がcopy-list-initialization/2がdirect-list-initializationですが、C++11/14/17いずれでも両者は同一です) 質問コードとの違いは、コメントの方はC++03だと両者ともNGになる点でしょうか。
nomi

2018/01/31 04:01

わかりました!!ありがとうございます!!
yohhoy

2018/01/31 07:22 編集

{と}を使ったリスト初期化(list initialization)は、初期化構文を便利にしようとC++11から広く導入されましたが、一部コーナーケースで微妙な問題をはらんでいる機能でもあります。 残念ながら「常にリスト初期化を使えばOK!」と断言できない状況のため、便利になる範囲で使っていけば良いのではとも思います。 # 書籍「Effective Modern C++」項目7:"オブジェクト作成時の()と{}の違い" などで詳細説明されています。
guest

0

ええっとC++に構造体はないのでクラスですね。

cpp

1RGB cube1 = {1, 5, 6}; // 方法1 2RGB cube2 = RGB{1, 5, 6}; // 方法2

この2つですが、今回は特殊な条件に当てはまるので得られる結果は同じとなりますが、C++規格的にはべつのものです。

C++のクラスにはコンストラクタや代入演算子と言った特殊なメンバ関数があり、ある特定の条件を満たすとこれらの一部ないし全てが自動で生成されます。その条件は複雑ですが、その説明は
C++入門者に贈るclass入門とclass/structキーワードの使い分け - Qiita#コンパイラによる暗黙宣言
に丸投げするとして、結論から言うと今回のRGBクラスは条件を満たしているのですべての特殊なメンバ関数が自動生成されます。

さて、方法1ですが、これはaggregate初期化です。コンストラクタによっては同様の記法でinitizer_listによる初期化とみなされることもあるからややこしい。
方法2も方法1と同じですが、ただし初期化したオブジェクト(RGB{1, 5, 6})をmoveして初期化しています(自信ない、C++17でRVO強制になったけどこれどう解釈されるんだ?1と完全同一になるのか・・・?)


追記

yohhoyさんの回答が正しいのでそれを見てください。

この2つですが、今回は特殊な条件に当てはまるので得られる結果は同じとなりますが、C++規格的にはべつのものです。

と言ったのは、例えば

std::vector<int> a1 = { 1, 2, 3 }; std::vector<int> a2 = std::vector<int>{ 1, 2, 3 };

この2つは(C++14までだと)違う挙動だよ、という意味合いの話でした。見かけ上すっごい似ていますよね?
C++17からはこれも同一の挙動になったはずなので、わかりやすくなった・・・のか?

投稿2018/01/29 17:18

編集2018/01/30 02:46
yumetodo

総合スコア5850

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

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

Chironian

2018/01/30 02:25 編集

この辺りは本当にややこしいですよね。 実はアグリゲート初期化良く判ってなかったです。 方法2が通るから、std::vector<RGB> x; x.emplace_back(1, 5, 6);も通りそうな気がしてたけど通らないのが謎でした。コンストラクタなしでできるのがアグリゲート初期化なのですね。emplace_back()は単にコンストラクタへ中継しているだけだから通らないんだとやっと悟りました。 ところで、方法2はムーブ・コンストラクタとは限らないと思います。コピー・コンストラクタの時もあると思います。ただ、通常はRVOが機能するから、直接アグリゲート初期化される筈ですね。でも、実際には呼ばれなくてもコピーとムーブのコンストラクタが両方とも無かったらダメだった筈。 C++17で強制になったのであれば、ムーブやコピーのコンストラクタなしでも通るようになったということかも。
nomi

2018/01/30 12:50

回答頂きありがとうございます。C++には構造体が無いんですか?
yumetodo

2018/01/30 13:53

ありません。C互換のクラスとしてPODなクラスなんて概念もありましたが、その概念も大きすぎるということでtrivialだとかstanderd-layoutだとかに細分化された挙句、PODという概念自体が消えそうになっています。
nomi

2018/01/31 04:00

なんか複雑ですね。。。
yohhoy

2018/01/31 07:09

(確かに技術的には「C++に構造体は無い」「struct/classいずれもクラスだ」は厳格な言い回しではあります。とはいえ慣例的には struct=構造体/class=クラス と使い分けますし、どの用語が相応しいかはTPO次第かと思います... 個人的には、C++言語仕様の議論をしている状況でもない限り、ざっくり"構造体"といってしまって差し支えないと考える派です。記事期待)
guest

0

意味としては同じなのでしょうか?

意味としては「違う」ものとなります。

cube1の方は、RGB構造体を既定のコンストラクタRGB(int a, int b, int c)で初期化するものです。既定のコンストラクタとは、コンストラクタの記述がない構造体(クラスも同様)で自動生成されるもので、この場合は単純にメンバ変数に値を設定します。

cube2の方は、まず既定のコンストラクタRGB(int a, int b, int c)で初期化した一時オブジェクトを生成し、それを既定のコピーコンストラクタでcube2にコピーします。

つまり、結果は同じですが挙動は若干異なります。cube2の方は、別にオブジェクトを作ってコピーするという手間が入る分、場合によってはわずかに遅くなります(ほとんどの場合無視できる程度ですが)。

初期化構文にはもう一つあります。

C++

1RGB cube3{1, 5, 6};

これは、意味としては方法1と同じです。というか、C++11で初期化リストの構文を拡張してこのような書き方が可能になりました。これによって方法2の書き方も可能になったわけです。

ちなみに、C++では構造体名(クラスも同様)は型名としても認識されるので、RGBの手前にstructを付ける必要はありません。

投稿2018/01/30 02:06

catsforepaw

総合スコア5938

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

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

yohhoy

2018/01/30 02:30

結果としては同じことなのですが、「既定のコンストラクタRGB(int a, int b, int c)」は生成されません/存在しません。yumetodoさん回答にあるように、ここではaggregate初期化というちょっと特殊な処理が行われます。いずれにせよ直接観測されるものではないので、説明上の話にすぎないのですけどね...
catsforepaw

2018/01/30 02:42

> 説明上の話にすぎないのですけどね... 一応質問者さんの理解度も考慮して回答するように心がけていますので、判りやすく書いたつもりなのですが、上級者には誤解を招いてしまったようです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問