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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

C++

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

Q&A

解決済

4回答

9891閲覧

オブジェクト指向のメモリ効率

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

C++

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

1グッド

4クリップ

投稿2018/07/17 03:43

オブジェクト指向ってメモリ効率が悪くないでしょうか??
オブジェクト指向についてまだ理解が不十分なので使い方がイマイチよくわかっていません。

「メモリ効率が悪いのでは??」と思ったのはメソッドです。(メンバ関数)
(ここで言うメソッドと関数は同じものとしますね。)

以下にテストした簡単なサンプル。

#include<iostream> class test{ public: void func(int&& y){ std::cout << y << std::endl; }; }; class same_func{ public: void func(int&& y){ std::cout << y << std::endl; }; }; class same_func_keishou : public same_func{ public: void other_func(int&& x){ std::cout << x << std::endl; }; }; int main(){ test check; check.func(1); same_func same; same.func(2); same_func_keishou keishou; keishou.func(3); keishou.other_func(77); return 0; }

以下、逆アセンブルした関数呼び出し部分です。

e8 b4 00 00 00 callq 980 <_ZN4test4funcEOi> 8e1: e8 d6 00 00 00 callq 9bc <_ZN9same_func4funcEOi> 8fb: e8 bc 00 00 00 callq 9bc <_ZN9same_func4funcEOi> 915: e8 de 00 00 00 callq 9f8 <_ZN17same_func_keishou10other_funcEOi>

全く同じ定義の関数が所属しているクラスが異なるだけで、2つの関数のための領域がメモリ上に確保されることになります。
「継承している場合は複数定義されることはない」ということのようです。

以下のような質問を見つけました。
C++でのクラスのメンバ関数が占める容量が知りたい

All instances share the same member function code.

まぁ・・・これはそうでしょうね。
インスタンスごとに異なる関数として定義されては、流石に効率が悪すぎます。

オブジェクト指向と10年戦ってわかったこと

継承は親クラスの機能を受け継ぎますが、これは開発効率を上げるための優しさ的仕様であり、継承の本質はインターフェイスなのです。もしあなたが継承の本質を「機能の受け継ぎ」と勘違いした途端、オブジェクト指向はあなたに牙を剥くでしょう。

むむ??
自分は今まで「継承」を「同じ関数を再度作るの面倒だから」・・・とか「この関数があれば便利だから」という理由で継承を利用していました。
ところが、この機能を受け継ぐという考え方はどうもダメみたいです。
(同じメソッドを使う場面が結構ありました。)

そうすると、同じメソッドもしくはif文などの条件分岐を少し加えるだけで、1つの関数にまとめられるような場合、どのようにしてプログラムを作れば良いのか??という疑問があります。
これは、C++に限った話ではないですね。

アプリケーション開発みたいに、最近のメモリは大量なのでこれくらいは大丈夫・・・という気がしますが・・・
OS開発や組み込み系の低レイヤーでは、同じ関数が別の物として複数定義されているのは、ちょっと効率が悪いですよね??
「塵も積もれば山となる」みたいな・・・

STLにそのようなメソッドがあるかどうか不明なのですが・・・
std::vector と std::stringについて試しに調べてみましたが、全くの別物でしたね。

//std::vector::push_back() #if __cplusplus >= 201103L void push_back(value_type&& __x) { emplace_back(std::move(__x)); } //std::string::push_back() void push_back(_CharT __c) { const size_type __size = this->size(); if (__size + 1 > this->capacity()) this->_M_mutate(__size, size_type(0), 0, size_type(1)); traits_type::assign(this->_M_data()[__size], __c); this->_M_set_length(__size + 1); }

ライブラリなどでこの・・・「同じ関数が別物として定義される」ものを作るとメモリ効率が下がりますよね。
特に、C++のような低レベルのプログラミングをジャンジャンできるような言語だとメモリを無駄遣いするわけにはいかないかと思います。

STLを眺めていて以下のような記述を目にしたことがあります。
(ちょっと違うかもしれません。)

push_back(){ _Base::push_back(); }

うーーーん。ちょっと微妙。
カプセル化に反する??
何度もよく使うようなメソッドをまとめといて、それを呼び出している感じですね。
これだと、C言語でオブジェクト指向プログラミングをしているのとあんまり変わらないような気がします。(Linux Kernelみたいな)

同じメソッド、あるいはかなり近い、似たようなメソッドを使いまわしたい場合、どうすればよいのでしょうか?

メモリ効率のモヤモヤ感とオブジェクト指向の考え方がちょっと難しいですね。
ポリモーフィズムなどはメモリを食いそうで仕方がないとという感じがしますが、Cに比べるとちょっとメモリ効率が悪い感じですかね。

分かる方教えてください。
環境は、Linux g++ でやりました。

退会済みユーザー👍を押しています

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

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

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

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

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

guest

回答4

0

ベストアンサー

同じメソッド、あるいはかなり近い、似たようなメソッドを使いまわしたい場合、どうすればよいのでしょうか?

さして容量が逼迫しているわけでもない状況下で、「容量的な意味で」使いまわしたいのであれば、その考えを捨ててください。僅かな容量を節約することによって得られるメリットと、手間やバグのリスクを考えれば、多くの場合は削減するメリットがありません。

ポリモーフィズムなどはメモリを食いそうで仕方がないとという感じがしますが、Cに比べるとちょっとメモリ効率が悪い感じですかね。

「はい、そのとおりです」以上のコメントはありません。テンプレート機能もあくまで「型だけ違う関数やクラスを、手間なく作れる」というものを意図したものなので、容量効率なんてことは基本的に考慮していません

特に、C++のような低レベルのプログラミングをジャンジャンできるような言語だとメモリを無駄遣いするわけにはいかないかと思います。

容量に制約がある場合は、C的な書き方に移ることもできる、というのがC++の魅力(魔力?)でもあります。

投稿2018/07/17 03:58

maisumakun

総合スコア145121

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

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

strike1217

2018/07/17 04:18

「その考えを捨ててください。」 というのは、「メモリ容量について気にするな!!」という意味です? 「その」といういのはメモリ効率についてでですよね? 「容量効率なんてことは基本的に考慮していません。 」 あ・・・そうなんですね。
strike1217

2018/07/17 04:21

「容量に制約がある場合は、C的な書き方に移ることもできる、というのがC++の魅力(魔力?)でもあります。」 な・なるほど!modern C++ と レガシーなCをうまいこと使い分けるんですね。
sazi

2018/07/17 05:02

strike1217 さん メモリー容量を意識する必要があるなら、そういう意識が反映できる言語を選択するということになりますから、選択した後に文句を言っても、ってことですね。
strike1217

2018/07/17 05:28

すいません。文句のつもりではありませんでした。 C言語の考え方がちょっと抜けなくて、C++でも同じようにメモリ効率を考慮するのかな?・・・というのが疑問だったので!
sazi

2018/07/17 05:38 編集

文句というのは単なる表現のつもりです。 メモリ容量をシビアに制御する必要があるなら、言語特性によるトレードオフなんかは事前に考慮すべきことで、順序が違うというのが伝えたい事です。 単に知りたかった故の質問であったということは理解しました。
strike1217

2018/07/17 05:39

あ!なるほど! わかりました。
zigutabi

2018/07/24 13:23

補足しますと、現状、家庭用ゲーム機ぐらいしかメモリ容量を気にする必要性は薄いです。加えて、オブジェクト指向はAndroidアプリ(made in java)になると、ルールと実装の明確化を可能にした側面もあります。これにより、ルール側でメモリを圧迫しないような書き方を指定できますので、規模が大きく複雑なものですと、かえってメモリ消費を抑えてくれます。
fa11enprince

2018/07/24 17:58

この程度のオーバーヘッドが問題になる環境って実は今はほぼ存在しないと思います。ゲームとかでは60fpsとか実現するのではnewするのが重いので、配置newっていうのを使ってあらかじめ確保したでかい領域をちまちま指定して使うことによりゼロオーバーヘッドで性能を劣化させることなく使ってるっていうのはたまに聞きます。
guest

0

Donald E. Knuthの格言に、

すべてとは言わないまでも、ほとんどすべての諸悪の根源は「早すぎる最適化」にある。

と申しますが、メモリ容量が実際に問題になってからメモリ最適化を考えたら良いんじゃないかなあ。

投稿2018/07/24 09:31

編集2018/07/24 09:32
chokojori

総合スコア971

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

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

strike1217

2018/07/24 10:12

なるほど!早いうちからメモリ効率など考えなくて良いということですかね。
chokojori

2018/09/26 00:55

そうです。 そのコードのメモリ効率が全体の性能を悪化させている、ということがプロファイラによって明らかになってから最適化に乗り出すので良いのです。 もうひとつの格言。 プログラムの処理時間の大半は、コードのごく一部に集中している。 逆に言えば、その「ごく一部」以外を最適化することは、プログラマーの時間の浪費である。
guest

0

push_back(){ _Base::push_back(); }

やはり、これを基本に工夫していけば良いのだと思います。

あるいは、フリー関数(非メンバ関数)で書いておいて必要に応じて呼び出すという手もあります。

投稿2018/07/17 09:50

編集2018/07/17 09:51
hayataka2049

総合スコア30933

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

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

strike1217

2018/07/17 10:01

ああ〜〜。 やはりそうですよね。 それぐらいしか思いつかないですね。
fana

2018/07/17 10:06

サンプルの複数のメソッドの実装が std::cout << y << std::endl; となっている時点で,「ostream.operator<<(int) の中身」という"同じ処理"をまとめることが既に達成できているように見える……
strike1217

2018/07/17 10:09

あくまでテスト用に作っただけなので、実際にはもっと複雑な関数の場合を想定してください。
fana

2018/07/17 11:48

どれだけ複雑だろうが,何らかの単位で{同じ,ほとんど同じ}処理をまとめたいのですよね? ならば,そのまとめたい部分に関して,こういうことをするだけなんじゃないの?ということを言っているのですが.
strike1217

2018/07/17 13:54

あ、そういうことですか。 失礼しました。
Kenji.Noguchi

2018/07/24 23:00 編集

完全に同じメソッドならMixinにするとかね。あ、メモリ効率が良くなるかはわかりませんが。
guest

0

たとえC言語でも、同じ動作をする関数を一つにまとめる、ような最適化するコンパイラは見たことないです

C

1 void A(int y){ 2 printf("%d",y); 3 } 4 void B(int y){ 5 printf("%d",y); 6 } 7 void C(int y){ 8 printf("%d",y); 9 }

ってあったとき、関数を一つしか生成しないコンパイラってどっかにあります?

投稿2018/07/17 04:04

y_waiwai

総合スコア87719

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

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

strike1217

2018/07/17 04:16

あーー。 説明が下手ですいません。 C言語のグローバルな関数を複数同じ物を定義するなんて場面はほとんどないですよね? その例だと、関数は1つで十分ですよね?わざわざ3つ用意する必要がありません。 自分の質問はC++のオブジェクト指向、class内のメンバ関数についてです。
y_waiwai

2018/07/17 04:21

Cでも実現できていないものがオブジェクト指向だから実現しないのはおかしいというのは、ちょっと間違ってると思いますけどねえ
strike1217

2018/07/17 04:29

「関数を一つしか生成しないコンパイラってどっかにあります?」 それは・・・おそらくないと思います。分かりません。見たことないです。 コンパイラの機能の話ではないです。 すいません・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問