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

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

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

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

Q&A

解決済

3回答

8274閲覧

メンバ変数の初期化を定義時にやるかコンストラクタでやるか

tokotaku

総合スコア63

C++

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

0グッド

1クリップ

投稿2021/11/29 05:35

編集2021/11/29 06:36

C++でのインスタンスに関する質問です。

インスタンスをヘッダファイル内で初期化することと、コンストラクタ等で初期化することに違いはあるのでしょうか?

例えば、MyClassA、MyClassB、MyClassCがあるとします。(それぞれのクラスの処理内容は省略します。)
MyClassBとMyClassCをMyClassAで利用するためにインスタンス化をする場合

MyClassA.h

#include "MyClassB.h" #include "MyClassC.h" class MyClassA { public: MyClassA(); private: MyClassB* myClassB = new MyClassB(this); //ここで先に初期化 MyClassC* myClassC; //宣言だけしてcpp内で初期化 }

MyClassA.cpp

#include "MyClassC.h" MyClassA::MyClassA(){ myClassC = new MyClassC(this); }

このMyClassBとMyClassCのインスタンスの初期化方法の違いでどちらが良いなどはあるのでしょうか?

様々なソースコードを読んでいると、ヘッダ内でインスタンス化と同時に行っているものもあればソース内で行っているものもありました。
調べてみても特にそういった話が見当たらないので、疑問に思いました。
これに関しては個人の好みの問題なのでしょうか?

また、調べている際に「インスタンス化」と「インスタンス生成」という2つの言葉があったのですが、この2つの違いはあるのでしょうか?

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

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

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

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

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

fana

2021/11/29 05:46 編集

> インスタンスをヘッダファイル内で初期化することと、コンストラクタ等で初期化することに違いはあるのでしょうか? > 様々なソースコードを読んでいると、ヘッダ内でインスタンス化と同時に行っているものもあればソース内で行っているものもありました。 情景がよくわからないので,記述の例を挙げるとよいかと思います. (「こういう書き方 と こういう書き方 があるのだけども…」という形で)
tokotaku

2021/11/29 06:08

簡単な具体例を追記しました。
int32_t

2021/11/29 06:34

タイトルは「メンバ変数の初期化を定義時にやるかコンストラクタでやるか」などがわかりやすいかと思います。
tokotaku

2021/11/29 06:36

タイトル変更行いました、アドバイスありがとうございます
guest

回答3

0

細々とした違いはあるので状況によるということになってしまいますが、他の方の回答として出ていない違いを挙げるとすれば優先度の違いがあります。

データメンバの宣言時に初期化式を書いても実際に初期化するタイミングはコンストラクタの起動時です。 初期化式とコンストラクタ定義における初期化リストの両方で同じデータメンバの初期化が書かれている場合にはコンストラクタのほうが優先され、初期化式は評価されません。 データメンバの初期化式はコンストラクタで初期化しなかった場合のデフォルト値であると考えることもできるでしょう。

cpp

1//foo.h 2 3struct foo { 4 int a=1; // foo(void) のほうを呼出した場合にはこの式の評価自体がされない 5 // foo(nullptr_t) のほうを呼出した場合には評価して 1 で初期化される 6 foo(void); 7 foo(nullptr_t); 8}; 9

cpp

1#include <iostream> 2#include <cstddef> 3#include "foo.h" 4 5foo::foo(void) : a(2) {} 6foo::foo(nullptr_t) {} 7 8int main(){ 9 foo bar; 10 // bar.a の内容は 2 になる 11 std::cout << bar.a << std::endl; 12 foo baz(nullptr); 13 // baz.a の内容は 1 になる 14 std::cout << baz.a << std::endl; 15 return 0; 16}

通例ではクラス定義はヘッダファイルに書くことも多いわけで、ユーザーがクラス構造を確認するためにヘッダファイルをみたときに a の初期値が何であるか見ることが出来れば便利なこともあるでしょう。 その一方ではヘッダファイルに書かれているのと異なる値で初期化されることがありうるというのは罠ポイントです。


オブジェクト指向一般ではクラスを実体化 (つまりオブジェクトの生成) することをインスタンス化と呼ぶこともありますが、 C++ の仕様におけるインスタンス化 (instantiation) はテンプレートから型や関数を生成する意味で使われていて、オブジェクトの生成の意味では使われません。

とはいえ現実には誰もが常に言語仕様の正確な用語法に従っているわけではありませんし、翻訳の段階で違う語があてられてしまう場合もありますし、どういう意味で使っているのかは文脈次第なところがありますね。

投稿2021/11/29 07:34

SaitoAtsushi

総合スコア5684

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

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

tokotaku

2021/11/30 04:52 編集

ありがとうございます。 初期化の方法やタイミングによっては、そういう点でも違いが出てくるとは思ってもいませんでした・・・ とても勉強になりました!
guest

0

ベストアンサー

MyClassB* myClassB = new MyClassB(this); //ここで先に初期化

これを行うためには,この時点で ClassB の定義が見えている必要があり,それ故に,例えばこれが書いてある MyClassA.h に #include "MyClassB.h" が書かれるような話になってきます.
しかし,MyClassA の利用者が MyClassB の存在を知らなくてよい場合,MyClassA.h の利用側(これをincludeする側)に余計なincludeを強いる形となります.

MyClassC* myClassC; //宣言だけしてcpp内で初期化

対してこちらの場合だと,#include "MyClassC.h" を MyClassA.h に書かずとも,Class MyClassC; という宣言だけで済ますことができるでしょう.


「インスタンス化」と「インスタンス生成」という2つの言葉

まぁ同じ意味かと.
(templateに関連する「インスタンス化」とかじゃなければ)

投稿2021/11/29 06:28

fana

総合スコア11996

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

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

fana

2021/11/29 06:41

個人的には,メンバ定義部での初期化自体あまり書いたことないな. 昔(いつ?)はできなかったし. (今できるとしても初期化を書く場所が時々であっちだったりこっちだったり…っていうのは何か嫌な感じ.)
fana

2021/11/29 07:58 編集

本件の質問内容とは関係ないけども, コンストラクタ内とかで this を他者に渡すってのは危険な香りがしますね. 絶賛初期化中のオブジェクトたる自身を指すポインタを介して何かされたらどうなってしまうのか…?っていう. --- 自分で書いててなんだけど,「絶賛初期化中」って日本語おかしいよね?
tokotaku

2021/11/30 04:48

ありがとうございます。 どの回答も納得できるもので大変参考になりました。 その中でも特に把握しやすかったものをベストアンサーとさせていただきます。
guest

0

通常、C/C++ のヘッダは、複数回 include されたとしても最初の一回しか処理しないように、#ifdef を使ってコントロールしています。これは定義の多重定義を避けるためですが、これを逆用すると、
「あるクラスのインスタンスがただ一つしか存在しない」状態を作り出せます。
※複数回のインスタンス化を阻止する

インスタンスの単一化を図るというのは Singleton デザインパターンとしてよく使われるものですが、その意味を持ってヘッダでインスタンス化もやっているのではないかと思います。

投稿2021/11/29 06:19

tacsheaven

総合スコア13703

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

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

episteme

2021/11/29 06:57

> 複数回 include されたとしても最初の一回しか処理しないように...「あるクラスのインスタンスがただ一つしか存在しない」状態を作り出せます。 どうやって? a.cpp と b.cpp が xxx.h を#includeしてたときにもそんなことできるん?
tacsheaven

2021/11/29 07:41

a.cpp でも b.cpp でもコンストラクタを呼び出さなければ問題ないですよね。 a.cpp と b.cpp のどちらもが xxx.h をインクルードしていたとしたら、先に処理された側でのみ #include "hhh.x" の処理がなされて(#ifdefによるガードで)、変数宣言がただ一回になりますから、そこでコンストラクタを呼び出してあるならば、インスタンスはただ一つになります。 ※ヘッダ内でコンストラクタを呼び出しているかどうか、a.cpp でも b.cpp でもコード書く時に確認するはずですね
episteme

2021/11/29 08:13 編集

...ごめんわかんない(スンマセン)。異なるコンパイル・ユニットで"先に処理"とは? #ifndef~ による include-guard はひとつのコンパイル・ユニット内での多重includeを抑止するもんだと。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問