getter 和 setter 会影响 C++/D/Java 中的性能吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1109995/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 15:13:25  来源:igfitidea点击:

Do getters and setters impact performance in C++/D/Java?

javac++d

提问by alvatar

This is a rather old topic: Are setters and getters good or evil?

这是一个相当古老的话题:setter 和 getter 是好还是坏?

My question here is: do compilers in C++ / D / Java inline the getters and setter?

我的问题是:C++/D/Java 中的编译器是否内联 getter 和 setter?

To which extent do the getters/setters impact performance (function call, stack frame) compared to a direct field access. Besides all the other reasons for using them, I would like to know whether they are supposed to affect the performance besides being a good OOP practice.

与直接字段访问相比,getter/setter 在多大程度上影响性能(函数调用、堆栈帧)。除了使用它们的所有其他原因之外,我想知道它们除了是一种良好的 OOP 实践之外是否应该影响性能。

采纳答案by jalf

It depends. There is no universal answer that is always going to be true.

这取决于。没有永远正确的普遍答案。

In Java, the JIT compiler will probably inline it sooner or later. As far as I know, the JVM JIT compiler only optimizes heavily used code, so you could see the function call overhead initially, until the getter/setter has been called sufficiently often.

在 Java 中,JIT 编译器可能迟早会内联它。据我所知,JVM JIT 编译器只优化大量使用的代码,因此您最初可以看到函数调用开销,直到 getter/setter 被足够频繁地调用。

In C++, it will almost certainly be inlined (assuming optimizations are enabled). However, there is one case where it probably won't be:

在 C++ 中,它几乎肯定会被内联(假设启用了优化)。但是,有一种情况可能不会:

// foo.h
class Foo {
private:
  int bar_;

public:
  int bar(); // getter
};

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

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

If the definition of the function is not visible to users of the class (which will include foo.h, but won't see foo.cpp), then the compiler may not be able to inline the function call.

如果函数的定义对类的用户不可见(将包含 foo.h,但不会看到 foo.cpp),那么编译器可能无法内联函数调用。

MSVC should be able to inline it if link-time code generation is enabled as an optimization. I don't know how GCC handles the issue.

如果启用链接时代码生成作为优化,MSVC 应该能够内联它。我不知道 GCC 如何处理这个问题。

By extension, this also means that if the getter is defined in a different .dll/.so, the call cannot be inlined.

通过扩展,这也意味着如果 getter 定义在不同的 .dll/.so 中,无法内联调用。

In any case, I don't think trivial get/setters are necessarily "good OOP practice", or that there are "all the other reasons for using them". A lot of people consider trivial get/setters to 1) be a sign of bad design, and 2) be a waste of typing.

无论如何,我不认为琐碎的 get/setter 是“良好的 OOP 实践”,或者“使用它们的所有其他原因”。很多人认为微不足道的 get/setter 是 1) 是糟糕设计的标志,2) 是对打字的浪费。

Personally, it's not something I get worked up about either way. To me, for something to qualify as "good OOP practice", it has to have some quantifiable positive effects. Trivial get/setters have some marginal advantages, and some just as insignificant disadvantages. As such, I don't think they're a good or bad practice. They're just something you can do if you really want to.

就个人而言,这不是我对任何一种方式都感到兴奋的事情。对我来说,要被称为“良好的 OOP 实践”,它必须具有一些可量化的积极影响。微不足道的 get/setter 有一些边际优势,也有一些同样微不足道的缺点。因此,我不认为它们是好或坏的做法。如果您真的愿意,它们只是您可以做的事情。

回答by dsimcha

In D, all methods of classes, but not structs, are virtual by default. You can make a method non-virtual by making either the method or the whole class final. Also, D has property syntax that allows you to make something a public field, and then change it to a getter/setter later without breaking source-level compatibility. Therefore, in D I would recommend just using public fields unless you have a good reason to do otherwise. If you want to use trivial getters/setters for some reason such as only having a getter and making the variable read-only from outside the class, make them final.

在 D 中,类的所有方法(但不是结构体)默认都是虚拟的。您可以通过使方法或整个类成为最终方法来使方法成为非虚拟方法。此外,D 具有属性语法,允许您将某些内容设为公共字段,然后在不破坏源代码级兼容性的情况下将其更改为 getter/setter。因此,在 DI 中建议只使用公共字段,除非您有充分的理由不这样做。如果您出于某种原因想使用简单的 getter/setter,例如只有一个 getter 并使变量从类外部变为只读,请将它们设为 final。



Edit:For example, the lines:

编辑:例如,行:

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

will work for both

对双方都有效

struct S
{
     int foo;
     int bar;
}

and

struct S
{
     void foo(int) { ... }
     int bar() { ... return something; }
}

回答by Arpad Kosa

I tried in Java: the same thing with and without getter and setter. The result: there is no significant difference between the execution time of the two versions. Here' s the code:

我在 Java 中尝试过:无论有没有 getter 和 setter,都是一样的。结果:两个版本的执行时间没有显着差异。代码如下:

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());
}

}

I know, at the end Bob is a bit older than me, but for this, it should be okay.

我知道,最后鲍勃比我大一点,但为此,应该没问题。

回答by Marenz

I had exactly the same question once.

我曾经有过完全相同的问题。

To answere it I programmed two small Programs:

为了回答它,我编写了两个小程序:

The first:

首先:

#include <iostream>

class Test
{
     int a;
};

int main()
{
    Test var;

    var.a = 4;
    std::cout << var.a << std::endl;
    return 0;
}

The second:

第二:

#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;
}

I compiled them to assembler, with -O3 (fully optimized) and compared the two files. They were identical. Without optimization they were different.

我将它们编译为汇编程序,使用 -O3(完全优化)并比较了两个文件。他们是相同的。如果没有优化,它们就不同了。

This was under g++. So, to answere your question: Compilers easily optimize getters and setters out.

这是在 g++ 下。所以,回答你的问题:编译器很容易优化 getter 和 setter。

回答by notnoop

Any JVM (or compiler) worth its salt needs to support inlining. In C++, the compiler inlines the getters and setters. In Java, the JVM inlines them at runtime after they have been called "enough" times. I don't know about D.

任何物有所值的 JVM(或编译器)都需要支持内联。在 C++ 中,编译器内联 getter 和 setter。在 Java 中,JVM 会在它们被调用“足够”次数后在运行时内联它们。我不知道 D。

回答by xtofl

Depending on the expected evolution of your class, get/setters may clutter your code vs. give you the flexibility to extend your implementation without affecting the client code.

根据您的类的预期演变,get/setter 可能会使您的代码变得混乱,而让您可以灵活地扩展您的实现而不影响客户端代码。

Often I encounter classes that are used as 'data containers', which have both getter and setter for each member. That's nonsense. If you don't expect to need some 'special' functionality to be triggered when getting or setting a member, don't write it.

我经常遇到用作“数据容器”的类,每个成员都有 getter 和 setter。那是胡说八道。如果您不希望在获取或设置成员时需要触发某些“特殊”功能,请不要编写它。

Given the speed of the machine, the effort of writing the extra abstraction will cost your clients more money.

考虑到机器的速度,编写额外抽象的工作将花费您的客户更多的钱。

Most compilers can optimize trivial getters/setters, but as soon as you declare them virtual (in C++), you pay an extra lookup - often worth the effort.

大多数编译器可以优化微不足道的 getter/setter,但是一旦您将它们声明为虚拟(在 C++ 中),您就需要进行额外的查找 - 通常值得付出努力。

回答by BCS

Quoting from hereRegarding the D Programming Langiage

这里引用关于 D 编程语言

I think DMD is currently unable to de-virtualize virtual getters and setters. Virtual calls are a bit slower by itself, but they also don't allow inlining, so successive standard optimizations can't be done. So if such accesses to the attribute is a virtual call and this happens in a "hot" part of the code, then it may slow down your code significantly. (if it happens in non-hot parts of the code it has usually no effects. That's why Java Hot Spot doesn't need optimize all your code to produce a very fast program anyway).

I have encouragedFrits van Bommel to improve the devirtualization capabilities of LDC:

Now LDC is able to do that in few very simple situations, but most times the situation is unchanged compared to DMD. Eventually LLVM will improve, so this situation can improve by itself. But the front-end too may do something about this.

Here is some documentation about this topic, some older, some more modern:

我认为 DMD 目前无法对虚拟 getter 和 setter 进行去虚拟化。虚拟调用本身有点慢,但它们也不允许内联,因此无法进行连续的标准优化。因此,如果对属性的此类访问是虚拟调用,并且这发生在代码的“热”部分,那么它可能会显着降低您的代码速度。(如果它发生在代码的非热点部分,它通常没有影响。这就是为什么 Java Hot Spot 不需要优化所有代码来生成一个非常快的程序)。

我鼓励Frits van Bommel 提高 LDC 的去虚拟化能力:

现在 LDC 能够在少数非常简单的情况下做到这一点,但与 DMD 相比,大多数情况下情况没有变化。最终 LLVM 会改进,所以这种情况可以自行改进。但是前端也可以对此做一些事情。

这是有关此主题的一些文档,一些较旧一些更现代

回答by Modicom

A getter would be required for certain members in some cases. However providing a getter and setter for each data member of a class is not a good practice. Doing that would be complicating the class's interface. Also setters would bring in resource ownership issues if not handled properly.

在某些情况下,某些成员需要一个 getter。然而,为类的每个数据成员提供 getter 和 setter 并不是一个好习惯。这样做会使类的接口复杂化。如果处理不当,setter 也会带来资源所有权问题。

回答by ChrisW

In C++, when a compiler's optimizations are enabled then getters and setters may be 'inlined': i.e., be implemented using the same machine instructions as there would be for direct access to the underlying member data.

在 C++ 中,当启用编译器的优化时,getter 和 setter 可以“内联”:即,使用与直接访问底层成员数据相同的机器指令来实现。

回答by Jay

I'll echo Xtofl.

我会回应 Xtofl。

Getters and setters are one of those things that are sometimes useful, but you get these doctrinaire people who somehow leap from "has proven useful in some cases" to "must be used all the time and if you don't use it you are a heretic who should be killed".

getter 和 setter 是有时有用的东西之一,但是你让这些教条主义的人不知何故从“在某些情况下证明有用”跃升为“必须一直使用,如果你不使用它,你就是一个应该杀的异端”。

If you have side effects to a get or set, by all means use a getter or setter.

如果您对 get 或 set 有副作用,请务必使用 getter 或 setter。

But if not, writing getters and setters just clutters up the code. There's a small performance penalty. In Java, if it's only executed a few times, the perforance penalty shouldn't matter, and if it's executed frequently, it should be inlined so the penalty is mitigated. So I'd worry more about making the code harder to read.

但如果没有,编写 getter 和 setter 只会使代码变得混乱。有一个小的性能损失。在 Java 中,如果它只执行几次,性能损失应该无关紧要,如果它经常执行,则应该内联以减轻性能损失。所以我更担心让代码更难阅读。

And don't for a minute buy the argument that this eliminates the problem of global data. Global data is bad and should be avoided. But declaring a member field private and then creating public getters and setters for does nothing to solve the problem.

并且不要相信这消除了全球数据问题的论点。全局数据不好,应该避免。但是将成员字段声明为私有,然后为其创建公共 getter 和 setter 并不能解决问题。