30


2

これはかなり古い話題です:セッターとゲッターは善か悪か?

私の質問はここにあります:C / D / Javaのコンパイラはゲッターとセッターをインライン化しますか?

直接フィールドアクセスと比較して、ゲッター/セッターはどの程度パフォーマンス(関数呼び出し、スタックフレーム)に影響を与えますか。 それらを使用する他のすべての理由に加えて、私はそれらがOOPの良い習慣であることに加えてパフォーマンスに影響を与えるはずであるかどうかを知りたいです。

10 Answer


23


場合によります。 常に真実になるだろうという普遍的な答えはありません。

Javaでは、JITコンパイラはおそらくそれをインラインでインライン化するでしょう。 私の知る限りでは、JVM JITコンパイラは使用頻度の高いコードを最適化するだけなので、getter / setterが十分に頻繁に呼び出されるまで、関数呼び出しのオーバーヘッドが最初に発生する可能性があります。

Cでは、ほとんど確実にインライン化されます(最適化が有効になっていると仮定して)。 しかし、おそらくそうならないケースが1つあります。

// foo.h
クラスFoo {private:int bar_;}

public:int bar(); //ゲッター};

// foo.cpp
#include "foo.h"

int Foo :: bar(){return bar_;} }

関数の定義がクラスのユーザーに見えない場合(foo.hを含みますがfoo.cppは表示されません)、コンパイラは関数呼び出しをインライン化できない可能性があります。

リンク時コード生成が最適化として有効になっている場合、MSVCはそれをインライン化できるはずです。 GCCがこの問題をどのように処理しているのかわかりません。

つまり、ゲッターが別の.dll / .soで定義されている場合、呼び出しはインライン化できません。

いずれにせよ、私は些細なget / settersが必ずしも「良いOOPプラクティス」であるとか、あるいは「それらを使用する他のすべての理由」があるとは思わない。 多くの人は、1)デザインが悪いことの兆候であり、2)入力の無駄であることを些細なget / settersと考えています。

個人的には、それは私がどちらの方法についても考え出すものではありません。 私にとって、「良いOOPプラクティス」としての資格を得るには、定量化できるプラスの効果があるはずです。 些細なget / settersにはいくつかの限界的な利点と、まったく同じくらい重要でない欠点があります。 そのように、私はそれらが良いやり方ではないと思います。 あなたが本当にしたいのなら彼らはあなたができることだけです。


9


Dでは、構造体ではなくクラスのすべてのメソッドはデフォルトで仮想です。 メソッドまたはクラス全体をファイナルにすることで、メソッドを非仮想にすることができます。 また、Dには、何かをパブリックフィールドにして、後でソースレベルの互換性を損なうことなくgetter / setterに変更できるプロパティ構文があります。 そのため、Dでは、あなたが他の方法で行うのに十分な理由がない限り、パブリックフィールドを使用することをお勧めします。 単にゲッターを持つことや変数をクラスの外から読み取り専用にすることなど、何らかの理由で簡単なゲッター/セッターを使いたい場合は、それらをfinalにしてください。

'' '' '

_Edit:_たとえば、次の行

S s; s.foo = s.bar 1;

両方のために働くでしょう

struct S {int foo;} intバー}

そして

struct S {void foo(int){... int bar(){... 何かを返す。 }}


6


私は一度だけ同じ質問をしました。

それに答えるために、私は二つの小さなプログラムをプログラムしました:

最初:

#含める

クラスTest {int a;} ;

int main(){テスト変数;

var.a = 4; std :: cout << var.a << std :: endl; 0を返します。 }

二番目:

#含める

クラスTest {int a;} int getA(){を返します。 void setA(int a_){a = a_;} ;}};

int main(){テスト変数;

var.setA(4); std :: cout << var.getA()<< std :: endl; 0を返します。 }

私はそれらを-O3(完全に最適化された)でアセンブラにコンパイルして、2つのファイルを比較しました。 それらは同一でした。 最適化がなければ、それらは異なりました。

これはgの下でした。 だから、あなたの質問に答えるために:コンパイラは簡単にゲッターとセッターを最適化します。


6


私はJavaで試した:ゲッターとセッターの有無にかかわらず同じこと。 その結果、2つのバージョンの実行時間に大きな違いはありません。 これがコードです:

クラスPerson {public int age;文字列名。 public Person(String name、int age){this.name = name; this.age =年齢}

クラスGetSetPerson {private int age;}文字列名。 public GetSetPerson(String name、int age){this.name = name; this.age =年齢public void setAge(int newage){年齢= newage;} public int getAge(){return age;}クラスProba {
//Math.hypot kb 10-szer lassabb, mint a Math.sqrt(x*xy*y)!!!

public static void main(String args []){長い開始時間、終了時間、時間; int i; int agevar;
//Person p1=new Person("Bob",21);
GetSetPerson p1 = new GetSetPerson( "Bob"、21); startTime = System.nanoTime(); / *(i = 0; i <1000000000; i){p1.age;

}

* /(i = 0; i <1000000000; i){agevar = p1.getAge(); agevar; p1.setAge(agevar); }

endTime = System.nanoTime(); time = endTime-startTime; System.out.println( ""時間); System.out.println(p1.name "の年齢は" p1.getAge())です。 }

}

私は知っている、最後にボブは私より少し年上ですが、これのために、それは大丈夫なはずです。


4


その塩の価値があるすべてのJVM(またはコンパイラ)はインライン展開をサポートする必要があります。 Cでは、コンパイラはゲッターとセッターをインライン化します。 Javaでは、JVMは「十分な」回数呼び出された後にランタイムにそれらをインライン化します。 私はDについて知りません。


4


予想されるクラスの進化に応じて、get / settersはあなたのコードを乱雑にするかもしれません。 クライアントコードに影響を与えずに実装を拡張するための柔軟性を提供します。

私はしばしば「データコンテナ」として使われるクラスに出会います。そしてそれは各メンバーのためのゲッターとセッターの両方を持っています。 それはナンセンスです。 メンバーを取得または設定するときに起動する特別な機能が必要ないと思われる場合は、それを作成しないでください。

マシンの速度を考えると、余分な抽象化を書くという努力はあなたのクライアントにより多くのお金をかけます。

ほとんどのコンパイラは簡単なゲッター/セッターを最適化することができますが、(C言語で)それらを仮想と宣言するとすぐに、余分な検索をすることになります。


3


場合によっては、特定のメンバーにゲッターが必要になります。 ただし、クラスの各データメンバーにゲッターとセッターを用意するのはお勧めできません。 そうすることはクラスのインターフェースを複雑にするでしょう。 セッターはまた、適切に処理されないとリソースの所有権の問題を持ち込むでしょう。


3


_ _ DMDは現在、仮想ゲッターとセッターの仮想化を解除できないと思います。 仮想呼び出しはそれ自体では少し遅くなりますが、インライン展開もできないため、連続した標準的な最適化は実行できません。 そのため、そのような属性へのアクセスが仮想呼び出しであり、これがコードの「ホット」部分で発生すると、コードが大幅に遅くなる可能性があります。 (それがコードのホットではない部分で起こったとしても、通常は効果がありません。 Java Hot Spotが非常に速いプログラムを作成するためにすべてのコードを最適化する必要がないのはそのためです。

http://www.dsource.org/projects/ldc/changeset/1506%3A76936858d1c6 [Frits van Bommel]はLDCの仮想化機能を改善することを推奨しています。

LDCは、ごく少数の非常に単純な状況でそれを実行できるようになりましたが、ほとんどの場合、状況はDMDと比べて変わりません。 最終的にLLVMは改善されるでしょう、それでこの状況はそれ自体で改善することができます。 しかし、フロントエンドもこれについて何かするかもしれません。

このトピックに関するドキュメントは、http://citeseerx.ist.psu.edu/viewdoc/download; jsessionid = B26C4304DB1DA05ECBD67CA7D9313511?doi = 10.1.1.7.7766&rep = rep1&type = pdf [some older]、http:// olsです。 fedoraproject.org/GCC/Reprints-2006/namolaru-reprint.pdf [もう少し現代的]: _ _


2


C言語では、コンパイラの最適化が有効になっている場合、ゲッターとセッターは「インライン化」されることがあります。


1


Xtoflをエコーし​​ます。

ゲッターとセッターは時々役立つそれらの物事のうちの1つです、しかし、あなたは何らかの形で「ある場合には役に立つことが証明された」から飛躍するこれらの教義的な人々を得る殺されるべき異端者だ "。

getまたはsetに副作用がある場合は、必ずgetterまたはsetterを使用してください。

しかしそうでなければ、ゲッターとセッターを書くことはコードを乱雑にするだけです。 わずかなパフォーマンスの低下があります。 Javaでは、それが数回しか実行されないのであれば、perforanceのペナルティは問題にならないはずです。頻繁に実行されるのであれば、インライン化することでペナルティは軽減されます。 だから私はコードを読みにくくすることについてもっと心配します。

そして、これがグローバルデータの問題を排除するという議論をちょっと買わないでください。 グローバルデータは悪く、避けるべきです。 しかし、メンバフィールドをprivateと宣言してからpublicゲッターとセッターを作成しても問題は解決しません。