• ベストアンサー

C++ データの扱い方の種類を教えて下さい

現在、資料の見よう見まねで機能毎にソースとヘッダを複数分けているのですが、 クラスを超えてデータを管理・変更する方法がわからずに、 現在全てのソースのヘッダーで 『extern』 宣言をして共有してしまっています。 (1変数・1配列単位でちまちまと。) できれば、 1.クラスを超えて、プログラムが終わるまで扱っていたいデータ。 2.数クラスをまたいだら、削除してしまいたいデータ。 に適した方法と 「データをまとめて扱い易くする方法」を詳しく教えて頂けると幸いです。 実装方法は自分で何とか頑張って勉強してみるつもりですので、 個人的な使い勝手で構いませんので『種類と用途』をどうか教えて下さい。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

 こんばんは。 ・1  シングルトン ・2  勝手に消えると言う事でしょうか? 其れならば、リファレンスカウンタ式のスマートポインタ辺りで良さそうです。  1の方はテンプレート化すると使いまわせます。但し、参照を返しているので、途中で消すのは帰って危険かもしれません。  アラもあるとは思いますが、以下参考程度に。 template<class __Tp> struct SingleTongue { typedef typename SingleTongue<__Tp> _Self; typedef typename __Tp value_type; typedef typename __Tp* pointer; typedef typename __Tp& reference; static reference GetInstance() { if(instance)return *instance; ::atexit(&_Self::Release); instance = new value_type(); return *instance; } static reference GetInstance(const _Self& r) { if(instance)return *instance; ::atexit(&_Self::Release); instance = new value_type(r); return *instance; } template<class __A> static reference GetInstance(const __A& a) { if(instance)return *instance; ::atexit(&_Self::Release); instance = new value_type(a); return *instance; } template<class __A, class __B> static reference GetInstance(const __A& a, const __B& b) { return GetInstance(value_type(a, b)); } private: static void Release() { delete instance; instance = NULL; } static pointer instance; }; template<class __Tp> typename SingleTongue<__Tp>::pointer SingleTongue<__Tp>::instance = NULL; struct MyData { explicit MyData(int _a = 0, int _b = 0) : a(_a), b(_b) { } int a; int b; }; int main() { typedef SingleTongue<MyData> STMyData; STMyData::reference rInst = STMyData::GetInstance(1); //以下の様にしても作成出来る //STMyData::reference rInst = STMyData::GetInstance(1, 2); //STMyData::reference rInst = STMyData::GetInstance(STMyData(2, 7)); rInst.a; rInst.b; return 0; }

zaxs5968
質問者

お礼

ご回答ありがとうございます。 シングルトン・スマートポインタ 両方初めて聞きました。 こういう方法が有るのですね。 軽く調べてみただけでも何やら良さそうな感じがします。 ご助言有難うございます!

その他の回答 (4)

  • BLK314
  • ベストアンサー率55% (84/152)
回答No.5

これって”設計"の問題ではないでしょうか? >「データをまとめて扱い易くする方法」 これには2段階あると思われます A.クラスレベルでまとめる   要するに関連するデータを1つのクラスでまとめて管理するということです B. モジュールレベルでまとめる   1クラスを1つのモジュールとしてとらえてもよいのですが、   非常に密接に関連する複数のクラスをまとめて1つのモジュールとしたほうが   分かりやすい場合もあります。   具体的には、ヘッダには外部へのインターフェースとなるクラス1つだけを書   き、cppにはそのクラスの実装とともに、内部的に使うクラスの宣言/実装も書  いてしまう方法です   おそらく、"数クラスをまたいだら削除してしまいたい"というのは   実装の都合上、一時的にだけ使われるようなデータを指すと思われます。   こういうのが、プログラム全体でどこからでもアクセスできてしまうのは   ”百害あって一理なし"なのでモジュール内に隠ぺい   (cppでstatic宣言する) するとプログラムの見通しが良くなると思います。   

zaxs5968
質問者

お礼

ご回答有難うございました。 私にはまだ難しいですが、将来的にはこういう事を当たり前に出来ないとまずいのですね。 ありがとうございました。 そしてこの場を借りて、 回答して下さった方々ありがとうございました。 新米でデータの管理はみんなどうしてるのか判らず 進むべき方法が判らなかったので、本当に勉強になりました。 別の問題に囚われ返答が遅くなって申し訳ありません。 メモにのこして順番に理解して行かせて頂きます。 みなさんありがとうございました。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.4

1.クラスを超えて、プログラムが終わるまで扱っていたいデータ。 2.数クラスをまたいだら、削除してしまいたいデータ。 両方ともですが、そのデータこそ「オブジェクト」なので組になるデータ単位でクラスにしてはいかがでしょう? 処理を主体で考えておられるようですが、データを主体に考えるのがオブジェクト指向です。データの処理は出来るだけクラスの内部に隠蔽して、外部とのやりとりはメンバ関数や演算子のオ-バロ-ドを通して行うべきだと思います。と言うかそうしないとクラスを使う意味が無い気がするんですが。 クラス化すれば、データの確保と削除はクラスのインスタンスの生成と消滅で制御できます。 [補足] 2.数クラスをまたいだら、削除してしまいたいデータ。 なんにしても確保したところと待ったく別の所で削除するのは危険極まりないので、確保したソースコードの見える範囲で必ず削除しましょう。

zaxs5968
質問者

お礼

ご回答ありがとうございました。 いつか利用できるよう勉強を進めて行きたいと思います。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

具体的に「こういう方法」というのは示しません. あと, 「どのくらい手間がかかるのか」も無視します. 「データをまとめて扱い易くする方法」というだけなら, 構造体なんてまさにそのためですよね. だから, 「論理的にまとめて管理しなきゃならないデータ群」を構造体としてまとめると簡単になったりする. その他の部分だけど, 「データの生存期間」だけを考えても無意味で, 「そのデータがどこで使われるのか」も考える必要があるんじゃないでしょうか. 「プログラムを実行している間保持しておかなきゃならないデータ」であっても, 「使う場所が限定されている」ならグローバルにする必要性はないです... というか, グローバルにするな. 「数クラスをまたいだら削除したいデータ」もグローバルに定義する価値はなくって, 必要なところで作って不要になったところで捨てればいい. 場合によっては shared_ptr あたりが使えるかもしれない. いずれにしても, 可能なら引数として渡すべきでしょう.

zaxs5968
質問者

お礼

>「そのデータがどこで使われるのか」も考える必要があるんじゃないでしょうか. そうですね、今はまだ頭がいっぱいいっぱいですが、 そういう事もいずれ考えられるように努力しようと思います。 >いずれにしても, 可能なら引数として渡すべきでしょう. そうですね・・今は引数はせめて3~4個と と決め付けていましたが 利用元が限られるのであればもっと引数に頼る方がシンプルで良いのかもしれませんね。 考え方等為になるご意見、ありがとうございました。

  • LOHA
  • ベストアンサー率52% (203/388)
回答No.2

>機能毎にソースとヘッダを複数分けている というのがちょっと良く分からないのですが、ヘッダファイル(.h)にはクラスや、関数、変数の宣言を、実装ファイル(.cpp)では、そのヘッダファイルをインクルードして、宣言したモノの定義を書くだけです。 で、別のファイルで定義したクラスを使いたいソースファイルがあったらその都度必要なヘッダファイルをインクルードすればいいはずです。 共通のヘッダファイルを色んなファイルでインクルードしたい場合は、インクルード処理をまとめたヘッダファイルを作成したりすれば楽です(ただし循環参照には気をつける)。 >1.クラスを超えて、プログラムが終わるまで扱っていたいデータ。 ですが、超楽ーに実装するのでしたら、グローバル変数にするのが手っ取り早いと思います(当然グローバル変数は避けた方がいいですが、名前空間とか使えばスコープを制限できるので工夫次第ですね)。 あるいはNo.1さんが挙げられているようにシングルトンパターンを利用するのも一つの手でしょう。

zaxs5968
質問者

お礼

>インクルード処理をまとめたヘッダファイルを作成したりすれば楽です 成る程、1cpp 1hという利用しかしていませんでしたが、そういう方法も有るのですね; >グローバル変数と名前空間 成る程。確かに名前付けが怖かったですが、名前空間を使えば便利な名前で使えるのですね。 今すぐにでも簡単に使えそうな方法のご紹介、本当にありがとうございます

関連するQ&A

  • C言語のヘッダファイルの使い方

    ヘッダファイルの使い方について質問です。 ソースファイルA、ソースファイルBで共有して使用したい変数がある場合、 Aでは「int a」と宣言し、Bでは「extern int a」と宣言すれば 同じ変数を共有出来ると認識しています。 それをヘッダファイルへ記述しておきたい場合にはどのように 宣言しておけば良いのでしょうか? ヘッダファイルに「int a」と宣言した場合は両方のソースファイルで includeした時に多重定義でエラーとなります。 では「extern int a」と宣言しておいて、両方のソースファイルで includeするのが正しいのでしょうか? 初歩的な質問で申し訳ないですが、有識者の方、教えてください。

  • 宣言と定義 通用範囲やインスタンス

    C++ビギナーの者です。 オブジェクト指向プログラムを見よう見まねでやって壁にぶつかっています。 わからない事が3つ程あります。 1. 「ヘッダーファイル中」と「ソースファイルの、関数・クラスの外側」と「その中」 この3箇所での、宣言や定義にはどんな制限等が存在するのでしょうか? ヘッダーに書くとダメなものが、ソースでならOKだったり混乱しています。 2. ClassAというクラスのインスタンスを、「複数の関数」で使いたい場合に  「ソースファイルの、関数・クラスの外側」 で ClassA classa; 等として、ソース内の複数の関数で利用するのは大間違いなのでしょうか? グローバル変数が何度も初期化されるトラブル等が起きています。 3. ソースファイルA側でデータを入れたvectorを ソースファイルB側で使うにはexternを付けるだけで良いのでしょうか? 手元にある参考資料から、見よう見まねでやってしまってるのですが、 C++の解説サイトにはあまり、こういった情報が載ってないのか見つけられません。 やはり書籍を買って勉強すべきだと痛感し始めたのですが、 解説のあるWebサイト、おすすめの書籍などが有りましたら それらも教えて頂けると幸いです。 よろしくお願いします っ_ _)っ

  • SolarisとLinuxのグローバル変数の扱いについて

    Solaris用のソースをLinuxで使えるように変更したいのですが、 グローバル変数について以下のようなことが発生していて困っています。 なにか、コンパイルオプションなどで対応はできないものでしょうか? Solaris (CC)では 特にextern宣言しなくても同じシンボルの外部変数はコモンセグメントに1つだけ作成しコンパイル自体は正常である。 しかし、Linux (g++)では externを宣言しないと同じシンボルを再定義したことになりエラーとなる。 これにより、グローバル変数を多用しているプログラムはLinuxでうまくコンパイルができない。 しかし、単純にextern宣言での対応は難しい。 extern宣言は外部で定義してあるグローバル変数を参照する というものだがLinux では 1つの定義を意外は全てexternしなければ、2重定義エラーになってしまう。 つまり、実体が1つであとはそれを参照しているという形でなければいけない。 ところが、その実体をどこにするか特定することができない。 例えば、gというグローバル変数を仮定する。 A.c,B.c,C.cはその3つのソースよりAA.aという静的ライブラリを構成する。 gはA.cで定義してありB.c,C.cはそれを参照する。 ところが C.cは個別にC.oというオブジェクトで他からの呼び出しがあり 別LMにリンクされる。 その時C.c内のgは実体を失うことになり未定義となる。 つまり、どれが実体になるかは何にリンクするかで決まるため 実態を特定できない。 また、共通のヘッダにグローバル変数が定義されている場合も、重複するというエラーを起こすため、 共通ヘッダからグローバル変数を分離し、何れかのソースにグローバル変数の実態を定義させる必要がある。 共通ヘッダを使っている他のソースはそのグローバル変数の実態を参照するようにexternの宣言をする。

  • 定義されているのにエラーになる

    閲覧ありがとうございます。 C言語のプログラムの話です。 ソースファイルaaa.cでstdio.hをincludeしています。 stdio.hには extern FILE _iob[_NIOBRW]; というのが定義されているにも関わらず、 コンパイルすると、 aaa.o:aaa.c:(.data+0x58): undefined reference to '_iob' というエラーが出ます。 aaa.cでは_iobに関する宣言はしていませんが、それを使うこともしていません。 ヘッダファイルでexternで宣言してるからかなと思い、ソースファイルにexternなしの宣言を書き足したら、コンパイルは通りました。 今回は元々既にあるプロジェクトの改修だったのですが、宣言を消したりしていません。 しかし、その部分は元々ヘッダファイルに宣言などしなくてもコンパイルが通ってました。 昔はヘッダファイルでexternで宣言してたらソースファイルではしなくてオッケーみたいな感じだったんですかね? 私自身、あまりよく分かってなくて文章もめちゃくちゃですみません。 不足している情報があればできる範囲でお伝えしますので、ご協力よろしくお願いいたします。

  • 自作ヘッダファイルについて (C言語)

    自作ヘッダファイルについて質問なのですが、ヘッダファイルには外部変数や関数のプロトタイプ宣言を記述しますよね?では関数の実装はどこで行ったらいいのでしょうか?回答よろしくお願いします。

  • 複数クラスで共通の関数、変数の呼び出し方

    お世話になります。 質問させて頂きたいことは 複数のクラスで共通して使われる関数、変数があった場合、その関数、変数は私の中で次の2通りの方法が思い当たったのですがどちらのほうがメモリ等の使用からよいのでしょうか? 1つめは あるヘッダファイル****.hを作成し、その中で関数を宣言し、変数はそのヘッダファイルのソースファイル中のグローバル変数とする。 2つめは クラスを作成し、静的メンバ関数、静的メンバ変数とする。 ネット等で拝見すると、あまりグローバル変数というのはよく見られていないようなので2つめの方がいいのかなと思っているのですが、静的メンバを今まで使ったことがないので、このような用途に使われるべきなのかも正直わかっていません。 検討外れのことを言っているのかもしれませんが、教えて頂ければと思っております。宜しくお願い致します。

  • ヘッダファイルにおける文字列リソース定義

    C言語(主にVC++)で開発をしていると、よく、 const char MSG_HELLO[] = "HELLO!"; のように、ヘッダファイル中で、文字列リテラルを定義します。 自分もいつのまにかこのようにリソース定義するようになっていましたが、初期の頃から疑問だったのは、extern宣言せずにchar配列を宣言しているから、コンパイラが最適化しなかったら、上記宣言のあるヘッダファイルを読み込んで、その定義を使った個所のあるソース分文字列リテラルがメモリ上に確保されてしまうのではないか、、?ということです。 つまり、本来なら const char* MSG_HELLO[] = "HELLO!"; とソースファイル中で定義し、ヘッダファイルには extern const char* MSG_HELLO; とすべきではないか、と思うわけです。ただ実際にこれをやっているとヘッダとソースの両方のメンテナンスが必要になるので、冒頭のように記述しているのだと思いますが。 この、本来なら下記のようにすべきだが、コンパイラの最適化(リソースのプール)を期待して最初のように書いている、という解釈は正しいでしょうか?

  • CとC++、どちらでコンパイルされているかをソース中で判別する方法

    タイトルのとおり、CとC++のどちらでコンパイルされているのかを、ソース中で判別する方法(#ifなど)を教えて下さい。 目的は、extern "C" という記述がCではエラーになってしまうのですが、CでもC++でもインクルード可能なヘッダファイルにするため、ヘッダファイル中で   #if「C++でコンパイル中」     extern "C" {   #endif としたいのです。 よろしくお願い致します。

  • データを取得し、その度に新しい配列に格納したい

    こんばんは。 CSVファイルのデータを読み込むクラスを作っています。CSVファイルは30ほどあるので、カンマで区切ったトークンの数(StringTokenizerで区切ったトークンの数)と行数はファイルによって違います。 1つのクラスを作り、データを配列に読み込ませたいと思います。Vectorクラスを使うと出来たのですが、全部String型なので、ストリング型の2重配列に読み込ませたいです。 最初に、配列の宣言をしたのでは、配列のサイズが決まってしまうので、データ数により、配列の大きさを変えたいのですが、うまい方法が見つかりません。 誰か分かる方は、教えてください。よろしくお願いします。

    • ベストアンサー
    • Java
  • ポインタによる包含&ヘッダにincludeしない、 場合でtemplateの定義に…

    class Bの宣言をしているヘッダ中で class A; を、前方宣言し、そのポインタだけを持たせ、ソースファイルのほうにclass Aの中身が分かるように、#includeして、ソースファイルに関数の実装やstatic変数の定義を書いていた、とします。 しかし、templateを使う関数についてはコンパイル時に解決できないといけないので、それだけはヘッダに持ってきました。 その時 includeが一切書かれていない、class Bのヘッダ内において class Aのメンバを参照するようなコードを書いたとき クラス外、クラス内、いずれに書いても 正常にコンパイルできました。 通常の関数では当然無理なので、もともとtemplateがコンパイル時解決を強要するものなのでそういう仕様にしててくれてると考えられますが 1.これは、C++の標準仕様でしょうか?それとも処理系依存でしょうか? あと、templateに関して 2.特殊化ならソースにかけるのは標準仕様でしょうか?それとも処理系依存でしょうか?

専門家に質問してみよう