Подтвердить что ты не робот

Усилители и сеттеры влияют на производительность на С++/D/Java?

Это довольно старая тема: являются ли сеттеры и геттеры хорошими или злыми?

Мой вопрос: компиляторы в С++/D/Java встроить геттеры и сеттер?

В какой степени производительность getters/setters влияет на производительность (вызов функции, стек кадров) по сравнению с прямым доступом к полю. Помимо всех других причин их использования, я хотел бы знать, должны ли они влиять на производительность, помимо хорошей практики ООП.

4b9b3361

Ответ 1

Это зависит. Нет универсального ответа, который всегда будет правдой.

В Java компилятор JIT, вероятно, рано или поздно включит его. Насколько мне известно, JVM JIT-компилятор только оптимизирует сильно используемый код, поэтому вы можете увидеть изначальный накладной вызов функции, пока геттер/сеттер не будут вызваны достаточно часто.

В С++ он почти наверняка будет встроен (при условии, что оптимизация включена). Однако есть один случай, когда он, вероятно, не будет:

// 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 справляется с проблемой.

Кроме того, это также означает, что если getter определен в другом .dll/.so, вызов не может быть встроен.

В любом случае, я не думаю, что тривиальные get/setters обязательно являются "хорошей практикой ООП" или что есть "все другие причины их использования". Многие люди считают, что тривиальные get/seters должны быть признаком плохого дизайна и 2) быть пустой трассировкой.

Лично я не работаю над тем или иным способом. Для меня, для того, чтобы квалифицироваться как "хорошая практика ООП", он должен иметь некоторые количественные положительные эффекты. Тривиальные get/seters имеют некоторые предельные преимущества, а некоторые - как незначительные недостатки. Таким образом, я не думаю, что это хорошая или плохая практика. Это то, что вы можете сделать, если захотите.

Ответ 2

В D все методы классов, но не структуры, по умолчанию являются виртуальными. Вы можете сделать метод не виртуальным, сделав либо метод, либо весь класс окончательным. Кроме того, D имеет синтаксис свойств, который позволяет вам сделать что-то публичное поле, а затем изменить его на getter/setter позже, не нарушая совместимость на уровне исходного кода. Поэтому в D я бы рекомендовал использовать только публичные поля, если у вас нет оснований для этого. Если вы хотите использовать тривиальные геттеры/сеттеры по какой-либо причине, такие как наличие только получателя и изменение переменной только для чтения вне класса, сделайте их окончательными.


Изменить: Например, строки:

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

будет работать как для

struct S
{
     int foo;
     int bar;
}

и

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

Ответ 3

У меня был один и тот же вопрос.

Чтобы ответить на это, я запрограммировал две небольшие программы:

Первое:

#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 (полностью оптимизированный) и сравнили два файла. Они были одинаковыми. Без оптимизации они были разными.

Это было под g++. Итак, чтобы ответить на ваш вопрос: компиляторы легко оптимизируют геттеры и сеттеры.

Ответ 4

Я пробовал на 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+" age now  is "+p1.getAge());
}

}

Я знаю, в конце Боб немного старше меня, но для этого все должно быть хорошо.

Ответ 5

Любой JVM (или компилятор), заслуживающий своей соли, должен поддерживать inlining. В С++ компилятор строит геттеры и сеттеры. В Java JVM объединяет их во время выполнения после того, как они были названы "достаточно". Я не знаю о D.

Ответ 6

В зависимости от ожидаемой эволюции вашего класса, get/setters могут загромождать ваш код и предоставлять вам гибкость для расширения вашей реализации, не затрагивая код клиента.

Часто я встречаюсь с классами, которые используются как "контейнеры данных", которые имеют как getter, так и setter для каждого члена. Это вздор. Если вы не ожидаете, что какая-то "специальная" функциональность будет запущена при получении или установке члена, не пишите его.

Учитывая скорость работы машины, усилие написания дополнительной абстракции будет стоить вашим клиентам больше денег.

Большинство компиляторов могут оптимизировать тривиальные getters/seters, но как только вы объявите их виртуальными (на С++), вы платите дополнительный поиск - часто стоит усилий.

Ответ 7

В некоторых случаях для некоторых участников потребуется геттер. Однако предоставление геттера и сеттера для каждого элемента данных класса не является хорошей практикой. Это усложнит интерфейс класса. Также сеттеры привносят проблемы с владением ресурсами, если их не обрабатывать должным образом.

Ответ 8

Цитата из здесь Что касается программирования Langiage D

Я думаю, что DMD в настоящее время не может де виртуализировать виртуальные геттеры и сеттеры. Виртуальные вызовы немного медленнее сами по себе, но они также не позволяют встраивать, поэтому последовательные стандартные оптимизации не могут быть выполнены. Поэтому, если такой доступ к атрибуту является виртуальным вызовом, и это происходит в "горячей" части кода, это может значительно замедлить ваш код. (если это происходит в не горячих частях кода, у него обычно нет эффектов. Поэтому Java Hot Spot не нуждается в оптимизации всего вашего кода для создания очень быстрой программы).

Я поощрял Frits van Bommel для улучшения возможностей девиртуализации LDC:

Теперь LDC может сделать это в нескольких очень простых ситуациях, но в большинстве случаев ситуация остается неизменной по сравнению с DMD. В конце концов LLVM улучшится, поэтому эта ситуация может улучшиться сама по себе. Но интерфейс тоже может что-то с этим поделать.

Вот несколько документов по этой теме, несколько старых, несколько более современных:

Ответ 9

В С++, когда оптимизация компилятора включена, геттеры и сеттеры могут быть "встроены": т.е. реализованы с использованием тех же машинных команд, что и для прямого доступа к данным базового элемента.

Ответ 10

Я буду эхо Xtofl.

Getters и seters - одна из тех вещей, которые иногда полезны, но вы получаете этих доктринерских людей, которые каким-то образом перескакивают с "доказали, что это полезно в некоторых случаях" для "должны использоваться все время и если вы его не используете" вы еретик, которого нужно убить ".

Если у вас есть побочные эффекты для получения или установки, обязательно используйте геттер или сеттер.

Но если нет, писать геттеры и сеттеры просто загромождает код. Там небольшой штраф за исполнение. В Java, если он выполняется только несколько раз, штраф за исполнение не должен иметь значения, и если он выполняется часто, он должен быть встроен, чтобы смягчить штраф. Поэтому я больше беспокоюсь о том, чтобы сделать код более трудным для чтения.

И ни на минуту не покупайте аргумент, что это устраняет проблему глобальных данных. Глобальные данные плохи и их следует избегать. Но объявление частного поля участника, а затем создание публичных геттеров и сеттеров для этого не делает ничего, чтобы решить проблему.