ゲッターとセッターは C++/D/Java のパフォーマンスに影響しますか?
質問
これはかなり古いトピックです。セッターとゲッターは善ですか、悪ですか?
ここでの私の質問は次のとおりです。C ++ / D / Javaのコンパイラはゲッターとセッターをインラインにしますか?
直接フィールド アクセスと比較して、ゲッター/セッターはパフォーマンス (関数呼び出し、スタック フレーム) にどの程度影響しますか。これらを使用する他の理由に加えて、OOP の優れた実践以外にパフォーマンスに影響を与えると考えられているかどうかを知りたいと思います。
解決
これは依存しています。常にtrueになるだろう普遍的な答えはありません。
Javaでは、JITコンパイラは、おそらくの遅かれ早かれのそれをインライン化します。ゲッター/セッターは十分に頻繁に呼び出されているまであなたは、最初に関数呼び出しのオーバーヘッドを見ることができるので、私の知る限りでは、JVMのJITコンパイラは、頻繁に使用されるコードを最適化します。
C ++では、ほぼ確実に(最適化が有効になっていると仮定して)インライン化されるであろう。しかし、一つのケースがある場合、それはおそらくではありません。
// foo.h
class Foo {
private:
int bar_;
public:
int bar(); // getter
};
// foo.cpp
#include "foo.h"
int Foo::bar(){
return bar_;
}
関数の定義は(foo.hというを含むであろうが、foo.cppは表示されません)クラスのユーザーに対して表示されない場合、コンパイラは、関数呼び出しをインライン化することができないかもしれません。
MSVCは、リンクタイムコード生成を最適化するように有効になっている場合、それをインライン化することができなければなりません。私はGCCの問題を処理する方法を知りません。
延長することで、これはまた、ゲッターが異なる.dllファイルで定義されている場合/ .soは、コールののインライン化することができないこと。
意味しますいずれにせよ、私は「それらを使用するための他のすべての理由」がある、またはあることささいなのget /セッターは必ずしも「良いOOPの実践」しているとは思いません。多くの人々は、悪いデザインの徴候である、および2)タイピングの無駄)1に些細GET / setterを検討します。
個人的に、それは私がいずれかの方法について後処理し得るものではないのです。私には、「良いOOPの実践」としての資格に何かのために、それはいくつかの定量化のプラスの効果を持っている必要があります。些細なGET /セッターは、いくつかの限界の利点、およびいくつかの同じように重要でない欠点を持っています。そのように、私は彼らが良いか悪い習慣だとは思いません。彼らはあなたが本当にしたい場合は行うことができますだけで何かです。
他のヒント
Dで、クラスではなく、構造体のすべてのメソッドは、デフォルトで仮想的です。あなたは、メソッドやクラス全体の最終のいずれかを行うことによって方法非仮想作ることができます。また、Dは、あなたが何か公共の場を作り、その後、ソースレベルでの互換性を壊すことなく、後にゲッター/セッターにそれを変更することができますプロパティの構文があります。したがって、Dに私はあなたがそうでなければ行うには良い理由がない限り、単にpublicフィールドを使用することをお勧めします。あなたは、このようなだけゲッターを持つ変数は読み取り専用クラスの外から行うことなど、いくつかの理由のために些細なゲッター/セッターを使用したい場合は、それらが最終的な作ります。
<時間>の編集:たとえば、行:
S s;
s.foo = s.bar + 1;
の両方のために動作します。
struct S
{
int foo;
int bar;
}
と
struct S
{
void foo(int) { ... }
int bar() { ... return something; }
}
私はJavaで試してみました:同じことをしてゲッターとセッターなし。結果:二つのバージョンの実行時間の間に有意差はありません。ここにコードがs:
class Person
{
public int age;
String name;
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
}
class GetSetPerson
{
private int age;
String name;
public GetSetPerson(String name,int age)
{
this.name=name;
this.age=age;
}
public void setAge(int newage)
{
age=newage;
}
public int getAge()
{
return age;
}
}
class Proba
{
//Math.hypot kb 10-szer lassabb, mint a Math.sqrt(x*xy*y)!!!
public static void main(String args[])
{
long startTime, endTime, time;
int i;int agevar;
//Person p1=new Person("Bob",21);
GetSetPerson p1=new GetSetPerson("Bob",21);
startTime=System.nanoTime();
/*
for (i=0;i<1000000000;i++)
{
p1.age++;
}
*/
for (i=0;i<1000000000;i++)
{
agevar=p1.getAge();
agevar++;
p1.setAge(agevar);
}
endTime=System.nanoTime();
time=endTime-startTime;
System.out.println(""+time);
System.out.println(p1.name+"'s age now is "+p1.getAge());
}
}
私が知っている、最後にボブは私より少し年上ですが、このために、それは大丈夫でなければなりません。
私はかつて、まったく同じ質問がありました。
私は二つの小さなプログラムをプログラムし、それをanswereするには
最初ます:
#include <iostream>
class Test
{
int a;
};
int main()
{
Test var;
var.a = 4;
std::cout << var.a << std::endl;
return 0;
}
第二
#include <iostream>
class Test
{
int a;
int getA() { return a; }
void setA(int a_) { a=a_; }
};
int main()
{
Test var;
var.setA(4);
std::cout << var.getA() << std::endl;
return 0;
}
私は-O3で、アセンブラにそれらをコンパイルした(完全に最適化されました) そして2つのファイルを比較しました。彼らは同一でした。 最適化がなければ、彼らは異なっていた。
このは、G ++下にありました。 だから、あなたの質問answereします。コンパイラは簡単にゲッターとセッターを最適化する
任意のJVM(またはコンパイラ)は、価値がその塩は、インライン化をサポートする必要があります。 C ++では、コンパイラはゲッターとセッターをインライン化。 Javaでは、JVMは、彼らが「十分に」回呼び出された後、実行時にそれらをインライン化。私はDのことは知らない。
あなたのクラスの予想進化に応じて、取得/セッターは対はあなたにクライアントコードに影響を与えることなく、あなたの実装を拡張するための柔軟性を与え、あなたのコードを散らかすことがあります。
多くの場合、私は、各メンバーのためのゲッターとセッターの両方を有する「データ・コンテナ」として使用されるクラスに遭遇します。それはナンセンスです。あなたはメンバーを取得または設定するときにトリガされるいくつかの特別な "機能を必要とすることを期待していない場合は、それを書いていない。
マシンのスピードを考えると、余計な抽象化を書くの努力はあなたのクライアントに多くのお金を費用がかかります。
ほとんどのコンパイラは、ささいなゲッター/セッターを最適化することができますが、できるだけ早くあなたは(C ++での)仮想それらを宣言するように、あなたは余分なルック支払う - 。努力が多いの価値を
ゲッターは、いくつかのケースでは、特定のメンバーのために必要とされるであろう。しかし、クラスの各データメンバーのためにゲッターとセッターを提供することは良い習慣ではありません。それを実行すると、クラスのインターフェイスを複雑になります。適切に処理されていない場合もセッターは、リソースの所有権の問題をもたらすでしょう。
からの引用 ここ Dプログラミング言語について
DMD は現在、仮想ゲッターとセッターを非仮想化できないと思います。仮想呼び出し自体は少し遅くなりますが、インライン化も許可されていないため、連続した標準の最適化を行うことはできません。したがって、このような属性へのアクセスが仮想呼び出しであり、これがコードの「ホット」部分で発生すると、コードの速度が大幅に低下する可能性があります。(コードの非ホット部分で発生した場合、通常は影響はありません。Java Hot Spot では、非常に高速なプログラムを作成するためにすべてのコードを最適化する必要がないのはこのためです)。
励ましてきました Frits van Bommel 氏は、LDC の非仮想化機能を改善しました。
現在、LDC はいくつかの非常に単純な状況でそれを行うことができますが、ほとんどの場合、状況は DMD と比べて変わりません。最終的には LLVM が改善されるため、この状況は自然に改善される可能性があります。しかし、フロントエンドもこれについて何かをするかもしれません。
C ++では、コンパイラの最適化は、次にイネーブルさゲッターとセッターは「インライン化」することができる場合:すなわち、下地部材データに直接アクセスするために存在するのと同じ機械語命令を使用して実施することが
Xtoflをエコーします。
ゲッターとセッターは、時々役立つものの 1 つですが、「場合によっては有用であることが証明されている」から「常に使用する必要があり、使用しないと役に立たない」になぜか飛躍する主義者がいます。殺されるべき異端者。」
get または set に副作用がある場合は、必ず getter または setter を使用してください。
しかし、そうでない場合は、ゲッターとセッターを作成してもコードが乱雑になるだけです。パフォーマンスに若干のペナルティが発生します。Java では、数回しか実行されない場合、パフォーマンス ペナルティは問題になりません。頻繁に実行される場合は、ペナルティを軽減するためにインライン化する必要があります。したがって、コードが読みにくくなるのではないかと心配しています。
そして、これによってグローバルデータの問題が解消されるという主張を少しも受け入れないでください。グローバルデータは悪いものなので、避けるべきです。しかし、メンバーフィールドをプライベートと宣言してからパブリックのゲッターとセッターを作成しても、問題は何も解決されません。