

初歩的な質問です。  
C/C++では、単純な型(intやdoubleなど)以外の型はポインタで確保、受け渡ししたほうが省メモリかつ高速にできることを知りました。  
自作クラスや構造体などは基本すべてポインタ(スマートポインタ)で宣言するべきなのでしょうか？ご回答よろしくお願いします。


CC BY-SA 3.0
2017-10-15T04:55:31.650
38713
2017-10-17T08:02:56.317
23768
question
c++ c ポインタ
C/C++のポインタで省メモリ/高速化をするにあたって


> C/C++では、単純な型(intやdoubleなど)以外の型はポインタで確保、受け渡ししたほうが省メモリかつ高速にできることを知りました。

どこで得た情報でしょうか？ 正確にはケースバイケースです。

> 自作クラスや構造体などは基本すべてポインタ(スマートポインタ)で宣言するべきなのでしょうか？

もちろんケースバイケースで一般論はありません。強いて言えば必要な場面でのみポインタを選択されるべきです。例えば呼び出し元と呼び出し先とで値を共有したくない場面ではポインタを使うべきではありません。またC++言語であれば、ポインタに代わる参照も提供されておりそちらの方が適切な場面も多いです。


CC BY-SA 3.0
2017-10-15T05:19:04.547
38715
2017-10-15T05:19:04.547
4236
38713
answer


> ポインタで確保

イマイチ意図がつかめませんが、

[code]

    int* n = new int(2);
    
[/code]

とかそういう話？動的確保はそれそのものがコストが掛かるのでむやみに使うべきではないですよね(なんのための自動変数領域)

よしんば動的確保するとして、C++の場合はスマートポインタ(`std::unique_ptr`など)ないしコンテナクラス(`std::vector`など)を利用するべきですから、ポインタの出番はありません

> ポインタで(中略)受け渡ししたほうが

C++においては大体の場面は参照を使うべきなので(nullにならない保証がある)やはりポインタの出番はありません。

それからC/C++共通して言えることとして、ポインタのdereferenceもコストがわずかながらかかるので、コピーコストとdereferenceコストとの兼ね合いになります。

ただし忘れては行けないのがコンパイラによる最適化で、頭の悪いポインタの使用はコンパイラの最適化を阻害します。


CC BY-SA 3.0
2017-10-16T13:45:55.827
38761
2017-10-16T13:45:55.827
23941
38713
answer


> C/C++では、単純な型(intやdoubleなど)以外の型はポインタで確保、受け渡ししたほうが省メモリかつ高速にできることを知りました。

以下の理由から、この文章は正しい認識とはいえません。

  * もっとも重要な「 **関数の引数として** 値を受け渡す」という情報が読み取れません。
  * 「ポインタで確保」が`new`や`malloc`による動的メモリ確保を指すのであれば、省メモリにも高速にもなりません。むしろ消費メモリ量はポインタ変数分だけふえてしまい、処理速度も低速になります。
  * いつでも「省メモリ」や「高速」になるとは限りません。比較的小さく単純な構造体(`std::pair<int,int>`や`std::complex<float>`など)では、ポインタ経由のメリットが失われることもあります。

もとの文意を残して修正するならば、次のような感じでしょうか：

「 **関数の引数として値を受け渡す** 場合に、単純な型(intやdoubleなど)以外の型は **ポインタもしくは参照** として受け渡ししたほうが、
**ほとんどのケースで** 省メモリかつ高速になる」

* * *

> 自作クラスや構造体などは基本すべてポインタ(スマートポインタ)で宣言するべきなのでしょうか？

この質問中の「宣言」が何を指すのか不明瞭ですが、短い回答としては「いいえ」。

「宣言」が自作クラスや構造体型`C`の変数宣言を意味するならば：

  * 基本的には、（ポインタや参照でない）通常の型 `C obj;` として宣言してください。
  * C++言語でオブジェクトを動的に確保する場合、スマートポインタ型 `std::unique_ptr<C> ptr;` や `std::shared_ptr<C> ptr;` として宣言してください。
  * C++言語で他変数の別名を付けたい場合、参照型 `C& ref = obj;` のように宣言してください。（あまり利用シーンは無いと思います）
  * C言語や、C++でどうしても避けられないときは、ポインタ型 `C* ptr;` を使わざるをえません。

「宣言」が関数パラメータの型宣言を意味するならば：

  * 関数処理がオブジェクトを変更しない場合は、 **const参照型`const C&`** として宣言してください。
  * 関数処理がオブジェクトを変更する場合は、参照型 `C&` か ポインタ型 `C*` を選ぶことになります。ヌルポインタを取りうるならば、ポインタ型を選ぶことになるでしょう。
  * 関数パラメータの型宣言でのスマートポインタ型(`std::unique_ptr<C>`,`std::shared_ptr<C>`,`std::weak_ptr<C>`)利用は、なれないうちは避けたほうが無難です。Herb Sutter氏による"[GotW #91 Solution: Smart Pointer Parameters](https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/)"やC++ Core Guildlinesの"[F.7: For general use, take T* or T& arguments rather than smart pointers](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-smart)"を参照ください。


CC BY-SA 3.0
2017-10-17T05:07:30.173
38778
2017-10-17T05:07:30.173
49
38713
answer


例えば1秒間の内に何回も頻繁に通信を繰り返すプログラムがあったとして、バッファを通信の都度確保／解放するとメモリの断片化が大量に発生する為、パフォーマンスが低下します。  
上記の様に頻繁に使用する場合はstatic宣言等で予め確保したバッファを使いまわすのも一つの手だと思います。

逆に滅多に使用されない画面クラスが存在したとして、その画面の為にメモリを確保し続ける必要は無いと思います。  
この辺りはプログラム設計を行う際、システムのリソースに合わせてエンジニアが最適化を行う必要があります。

RTOS等でメモリ管理を厳密に行う場合以外、そこまで神経質になる必要は無いと思います。  
パフォーマンスを完全に優先する場合、メモリは動的確保しない方が高速になりますが、大規模アプリの場合は適宜メモリを開放しないとリソースが枯渇して身動きが取れなくなるので、やはりケースバイケースです。

この辺りは、プログラムの規模、リソースの使用頻度と相談して常に最適解を探っていくしかないのではないでしょうか。


CC BY-SA 3.0
2017-10-17T08:02:56.317
38795
2017-10-17T08:02:56.317
22484
38713
answer