Domanda

Questo è un argomento piuttosto vecchio:? I setter e getter buoni o cattivi

La mia domanda è: che fare in compilatori C ++ / D / Java inline i getter e setter?

Al che misura le prestazioni impatto getter / setter (chiamata di funzione, telaio stack) rispetto ad un campo accesso diretto. Oltre a tutte le altre ragioni per il loro utilizzo, vorrei sapere se si suppone che influire sulle prestazioni oltre ad essere una buona pratica OOP.

È stato utile?

Soluzione

Dipende. Non esiste una risposta universale che sta andando sempre essere vero.

In Java, il compilatore JIT sarà probabilmente inline è prima o poi . Per quanto ne so, il compilatore JVM JIT ottimizza solo il codice usato pesantemente, così si poteva vedere l'overhead funzione di chiamata inizialmente, fino a quando il getter / setter è stato chiamato sufficientemente spesso.

In C ++, sarà quasi certamente essere inline (ottimizzazioni assumendo sono abilitati). Tuttavia, v'è un caso in cui probabilmente non sarà:

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

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

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

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

Se la definizione della funzione non è visibile agli utenti della classe (che comprenderanno foo.h, ma non vedranno foo.cpp), quindi il compilatore può non essere in grado di inline la chiamata di funzione.

MSVC dovrebbe essere in grado di inline se la generazione di codice di collegamento in tempo è abilitato come un'ottimizzazione. Io non so come GCC gestisce la questione.

Per estensione, ciò significa anche che se il getter viene definito in un dll diverso / .so, la chiamata possono non essere inline.

In ogni caso, non credo che banali get / set internazionale sono necessariamente "pratica buona programmazione orientata agli oggetti", o che ci sono "tutte le altre ragioni per il loro utilizzo". Un sacco di persone considerano banali GET / setter a 1) essere un segno di cattiva progettazione, e 2) una perdita di battitura.

Personalmente, non è qualcosa che vengo lavorato su circa in entrambi i casi. Per me, per qualcosa di qualificarsi come "buona pratica OOP", deve avere alcuni effetti positivi quantificabili. Trivial GET / setter hanno alcuni vantaggi marginali, e alcuni svantaggi altrettanto insignificanti. In quanto tale, non penso che siano una pratica buona o cattiva. Sono solo qualcosa che si può fare se si vuole veramente.

Altri suggerimenti

In D, tutti i metodi di classi, ma non struct, sono virtuali per impostazione predefinita. È possibile effettuare un metodo non virtuale, rendendo il metodo o l'intera classe finale. Inoltre, D ha una sintassi proprietà che ti permette di fare qualcosa di un campo pubblico, e quindi si cambia in una getter / setter in seguito senza rompere la compatibilità a livello di sorgente. Pertanto, in D mi sento di raccomandare usando solo i campi pubblici a meno che non si dispone di una buona ragione per fare altrimenti. Se si desidera utilizzare banali getter / setter per qualche motivo, come solo avere un getter e rendendo la variabile di sola lettura al di fuori della classe, li rendono finale.


Modifica: Ad esempio, le linee:

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

lavorerà sia per

struct S
{
     int foo;
     int bar;
}

e

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

ho provato in Java: la stessa cosa con e senza getter e setter. Il risultato: non ci sono differenze significative tra il tempo di esecuzione delle due versioni. Qui' il codice:

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

}

Lo so, alla fine Bob è un po 'più grande di me, ma per questo, dovrebbe essere a posto.

Ho avuto esattamente la stessa domanda una volta.

Per answere che ho programmato due piccoli programmi:

La prima:

#include <iostream>

class Test
{
     int a;
};

int main()
{
    Test var;

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

La seconda:

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

li ho compilato a assembler, con -O3 (completamente ottimizzato) e confrontato i due file. Erano identici. Senza l'ottimizzazione erano diversi.

Questa era sotto g ++. Quindi, per answere tua domanda:. Compilatori ottimizzare facilmente getter e setter fuori

Ogni JVM (o compilatore) degno deve supportare inline. In C ++, il compilatore Inlines i getter e setter. In Java, la JVM li Inlines in fase di esecuzione dopo che sono stati chiamati tempi "abbastanza". Non so su D.

In funzione dell'evoluzione prevedibile della classe, ottengono / setter possono ingombrare il codice di contro vi darà la flessibilità necessaria per estendere l'implementazione senza alterare il codice del client.

Spesso ho incontrato le classi che vengono utilizzati come 'contenitori di dati', che hanno sia getter e setter per ogni membro. Che è una sciocchezza. Se non si prevede di utilizzare alcune funzionalità 'speciale' da attivare quando ottenere o impostare un membro, non scriverlo.

Data la velocità della macchina, lo sforzo di scrivere l'astrazione in più avrà un costo di vostri clienti più soldi.

La maggior parte dei compilatori possono ottimizzare banali getter / setter, ma non appena li si dichiara virtuale (in C ++), si paga una ricerca in più -. Spesso vale la pena

Un getter sarebbe richiesto per alcuni membri in alcuni casi. fornendo tuttavia un getter e setter per ogni membro di dati di una classe non è una buona pratica. Facendo che sarebbe complicare l'interfaccia della classe. Anche setter avrebbe portato in questioni legate alla proprietà di risorse se non gestita correttamente.

qui Per quanto riguarda la D Programmazione Langiage

  

Credo DMD è attualmente in grado di de-virtualizzare getter e setter virtuali. chiamate virtuali sono un po 'più lento di per sé, ma anche non consentono inline, così successive ottimizzazioni standard non può essere fatto. Quindi, se tali accessi al attributo è una chiamata virtuale e questo accade in una parte "calda" del codice, allora può rallentare in modo significativo il proprio codice. (Se succede in parti non calde del codice che di solito ha alcun effetto. Ecco perché Java Hot Spot non ha bisogno di ottimizzare tutto il codice per produrre un programma molto veloce in ogni caso).

     

ho incoraggiato Frits van Bommel per migliorare le capacità devirtualization di LDC:

     

Ora LDC è in grado di farlo in alcune situazioni molto semplici, ma il più delle volte la situazione è invariata rispetto al DMD. Alla fine LLVM migliorerà, per cui questa situazione può migliorare da sola. Ma anche il front-end può fare qualcosa per questo.

     

Ecco po 'di documentazione su questo argomento, un po 'più vecchio , po' più moderno :

In C ++, quando ottimizzazioni del compilatore sono attivate quindi getter e setter possono essere 'inline':. Cioè, essere implementata utilizzando le stesse istruzioni macchina come ci sarebbe per l'accesso diretto ai dati utente sottostanti

Ti eco Xtofl.

getter e setter sono una di quelle cose che a volte sono utili, ma si ottiene queste persone che in qualche modo dottrinari salto da "si è dimostrata utile in alcuni casi" a "deve essere utilizzato tutto il tempo e se non ne fanno uso sei un eretico che dovrebbe essere ucciso".

Se si dispone di effetti collaterali di un GET o un insieme, con tutti i mezzi utilizzano un getter o setter.

Ma se non, scrivendo getter e setter pochi ingombra il codice. C'è una piccola riduzione delle prestazioni. In Java, se è eseguito solo un paio di volte, la pena dovrebbe perforance non importa, e se è eseguito di frequente, dovrebbe essere inline quindi la penalità è mitigato. Così mi preoccupo più di fare il codice più difficile da leggere.

E non per un minuto comprare l'argomento che questo elimina il problema dei dati globali. dati globali è male e deve essere evitato. Ma dichiarando un campo membro privato e quindi la creazione di getter e setter pubbliche per non fa nulla per risolvere il problema.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top