Γιατί να χρησιμοποιήσετε = για να προετοιμάσετε ένα πρωτόγονο είδος σε C ++;

ψήφοι
8

Όπου εργάζομαι, οι άνθρωποι συνήθως πιστεύουν ότι τα αντικείμενα είναι καλύτερο να αρχικοποιηθεί με τη χρήση C ++ - κατασκευή στυλ (με παρένθεση), ενώ πρωτόγονα είδη πρέπει να αρχικοποιηθεί με το = χειριστή:

std::string strFoo( Foo );
int nBar = 5;

Κανείς δεν φαίνεται να είναι σε θέση να εξηγήσουν γιατί προτιμούν τα πράγματα με αυτόν τον τρόπο, όμως. Μπορώ να δω ότι std::string = Foo;θα ήταν αναποτελεσματική, διότι συνεπάγεται ένα επιπλέον αντίγραφο, αλλά τι είναι λάθος με μόλις διώχνοντάς τον =χειριστή συνολικά και χρησιμοποιώντας παρενθέσεις παντού;

Είναι μια κοινή σύμβαση; Ποιο είναι το σκεπτικό πίσω από αυτό;

Δημοσιεύθηκε 09/12/2008 στις 18:52
πηγή χρήστη
Σε άλλες γλώσσες...                            


9 απαντήσεις

ψήφοι
17

Αρχικοποίηση μεταβλητών με το = χειριστή ή με ένα τηλεφώνημα κατασκευαστή είναι σημασιολογικά η ίδια, είναι απλώς ένα θέμα του στυλ. Προτιμώ το = χειριστή, αφού διαβάζει πιο φυσικό τρόπο.

Χρησιμοποιώντας το = χειριστή συνήθως δεν δημιουργεί ένα επιπλέον αντίγραφο - ακριβώς ζητά η κανονική κατασκευαστή. Σημειώστε, ωστόσο, ότι με μη-πρωτόγονες μορφές, αυτό είναι μόνο για προετοιμασίες που λαμβάνουν χώρα ταυτόχρονα με τις δηλώσεις. Συγκρίνω:

std::string strFooA("Foo");  // Calls std::string(const char*) constructor
std::string strFoo = "Foo";  // Calls std::string(const char*) constructor
                             // This is a valid (and standard) compiler optimization.

std::string strFoo;  // Calls std::string() default constructor
strFoo = "Foo";      // Calls std::string::operator = (const char*)

Όταν έχετε μη τετριμμένο προεπιλογή κατασκευαστές, η τελευταία κατασκευή μπορεί να είναι ελαφρώς πιο αναποτελεσματική.

Το πρότυπο C ++ , τμήμα 8.5, παράγραφος 14 αναφέρει:

Σε αντίθετη περίπτωση (δηλαδή, για τις υπόλοιπες περιπτώσεις copy-αρχικοποίηση), μια προσωρινή δημιουργείται. Αλληλουχίες μετατροπής ορίζονται από το χρήστη που μπορεί να μετατρέψει από το είδος της πηγής στον τύπο προορισμού ή ένα παραγόμενη κλάση αυτών που απαριθμήθηκαν (13.3.1.4), και το καλύτερο επιλέγεται μέσω ψηφίσματος υπερφόρτωσης (13.3). Η μετατροπή ορίζονται από το χρήστη έτσι επιλεγμένο καλείται να μετατρέψει την έκφραση initializer σε ένα προσωρινό, των οποίων ο τύπος είναι ο τύπος που επιστρέφεται από την κλήση της συνάρτησης μετατροπής ορίζονται από το χρήστη, με τα CV-προκριματικά του τύπου προορισμού. Εάν η μετατροπή δεν μπορεί να γίνει ή να είναι ασαφής, η αρχικοποίηση της κακής σχηματίζεται. Το αντικείμενο αρχικοποιείται είναι τότε απευθείας αρχικοποιείται από την προσωρινή σύμφωνα με τους ανωτέρω κανόνες. 87 ) Σε ορισμένες περιπτώσεις, η εφαρμογή επιτρέπεται να εξαλείψει την προσωρινή με την προετοιμασία άμεσα το αντικείμενο? βλέπε 12.2.

Μέρος του άρθρου 12.2 αναφέρει:

Ακόμα και όταν η δημιουργία της προσωρινής αντικειμένου αποφεύγεται, όλοι οι σημασιολογικές περιορισμοί πρέπει να τηρείται σαν να δημιουργήθηκε η προσωρινή αντικείμενο. [Παράδειγμα: έστω και αν ο κατασκευαστής αντίγραφο δεν καλείται, όλες οι σημασιολογικές περιορισμούς, όπως η προσβασιμότητα (11), πρέπει να πληρούνται. ]

Απαντήθηκε 09/12/2008 στις 18:57
πηγή χρήστη

ψήφοι
11

Απλά ένιωσα την ανάγκη για μια άλλη ανόητη θέση litb.

string str1 = "foo";

ονομάζεται copy-προετοιμασία , γιατί αυτό που κάνει ο compiler, αν δεν κατέλυε κάθε προσωρινές αποκαταστάσεις, είναι:

string str1(string("foo")); 

δίπλα ελέγχοντας ότι ο κατασκευαστής μετατροπής που χρησιμοποιείται είναι σιωπηρή. Στην πραγματικότητα, όλοι οι έμμεσες μετατροπές που ορίζονται από το πρότυπο όσον αφορά την αντιγραφή προετοιμασίας. Λέγεται ότι μια σιωπηρή μετατροπή από τον τύπο U προς τον τύπο Τ είναι έγκυρη, εάν

T t = u; // u of type U

είναι έγκυρο.

Σε αντίθεση,

string str1("foo");

κάνει ακριβώς ό, τι είναι γραμμένο, και ονομάζεται άμεση εκκίνηση . Συνεργάζεται επίσης με ρητή κατασκευαστές.

Με την ευκαιρία, μπορείτε να απενεργοποιήσετε eliding από προσωρινές αποκαταστάσεις με τη χρήση -fno-Elide-κατασκευαστές:

-fno-elide-constructors
    The C++ standard allows an implementation to omit creating a temporary which 
    is only used to initialize another object of the same type. Specifying this 
    option disables that optimization, and forces G++ to call the copy constructor 
    in all cases.

Το Πρότυπο λέει ότι δεν υπάρχει σχεδόν καμία διαφορά μεταξύ των

T a = u;

και

T a(u);

αν T και το είδος του u είναι πρωτόγονες μορφές. Έτσι, μπορείτε να χρησιμοποιήσετε και τις δύο μορφές. Νομίζω ότι είναι ακριβώς το στυλ του αυτό που κάνει τους ανθρώπους να χρησιμοποιούν την πρώτη μορφή και όχι τη δεύτερη.


Μερικοί άνθρωποι μπορούν να χρησιμοποιούν την πρώτη σε κάποια κατάσταση, επειδή θέλουν να αποσαφηνίζουν τη δήλωση:

T u(v(a));

migh φαίνονται σε κάποιον σαν τον ορισμό μιας μεταβλητής uπου έχει προετοιμαστεί χρησιμοποιώντας μια προσωρινή ενός τύπου vπου παίρνει μια παράμετρο για κατασκευαστή που ονομάζεται a. Αλλά στην πραγματικότητα, αυτό που ο compiler κάνει με αυτό είναι το εξής:

T u(v a);

Δημιουργεί μια δήλωση συνάρτηση που παίρνει ένα επιχείρημα του τύπου v, και με μια παράμετρο που ονομάζεται a. Έτσι κάνουν οι άνθρωποι

T u = v(a);

για να αποσαφηνίζουν ότι, παρόλο που θα μπορούσαν να έχουν κάνει

T u((v(a)));

πάρα πολύ, γιατί εκεί δεν είναι ποτέ παρενθέσεις γύρω από τις παραμέτρους λειτουργίας, ο compiler θα το διαβάσει ως μεταβλητή ορισμός αντί της δήλωσης συνάρτησης πάρα πολύ :)

Απαντήθηκε 09/12/2008 στις 19:21
πηγή χρήστη

ψήφοι
4

Αν δεν έχετε αποδείξει ότι έχει σημασία όσον αφορά την απόδοση, δεν θα ανησυχείτε για ένα επιπλέον αντίγραφο χρησιμοποιώντας τον τελεστή εκχώρησης στο παράδειγμά σας ( std::string foo = "Foo";). Θα ήμουν πολύ έκπληκτος εάν το αντίγραφο αυτό υπάρχει ακόμα και τη στιγμή που θα δούμε το βελτιστοποιημένο κώδικα, πιστεύω ότι θα καλέσει πραγματικά την κατάλληλη παραμετροποιημένη κατασκευαστή.

Σε απάντηση στην ερώτησή σας, ναι, θα έλεγα ότι είναι μια αρκετά κοινή σύμβαση. Κλασικά, οι άνθρωποι έχουν χρησιμοποιήσει αποστολή για την προετοιμασία ενσωματωμένων τύπων, και δεν υπάρχει επιτακτικός λόγος για να αλλάξει την παράδοση. Αναγνωσιμότητα και η συνήθεια είναι απολύτως βάσιμοι λόγοι για αυτή την σύμβαση με δεδομένο το πόσο μικρή επίπτωση που έχει στην απόλυτη κώδικα.

Απαντήθηκε 09/12/2008 στις 18:59
πηγή χρήστη

ψήφοι
2

Θα βρείτε πιθανώς αυτόν τον κώδικα, όπως

std::string strFoo = "Foo";

θα αποφύγει να κάνει ένα επιπλέον αντίγραφο, ο οποίος συγκεντρώνει στον ίδιο κωδικό (μία κλήση από ένα ενιαίο επιχείρημα κατασκευαστή) και το ένα με παρενθέσεις.

Από την άλλη πλευρά, υπάρχουν περιπτώσεις όπου πρέπει να χρησιμοποιήσετε παρενθέσεις, όπως μια λίστα εκκίνησης μέλος κατασκευαστή.

Νομίζω ότι η χρήση του = ή παρένθεση για να κατασκευάσει τις τοπικές μεταβλητές είναι σε μεγάλο βαθμό θέμα προσωπικής επιλογής.

Απαντήθηκε 09/12/2008 στις 18:57
πηγή χρήστη

ψήφοι
1

Λοιπόν, ποιος ξέρει τι θα σκέφτονται, αλλά εγώ προτιμώ και τα = για πρωτόγονα είδη, κυρίως επειδή δεν είναι αντικείμενα, και επειδή αυτή είναι η «συνήθης» τρόπος για να τους προετοιμάσει.

Απαντήθηκε 09/12/2008 στις 18:58
πηγή χρήστη

ψήφοι
0

Στη συνέχεια, όμως μόνο για να συγχέουμε σας ακόμα περισσότερο προετοιμαστεί πρωτόγονων στη λίστα εκκίνηση χρησιμοποιώντας τη σύνταξη αντικειμένου.

foo::foo()   
  ,anInt(0)   
  ,aFloat(0.0)   
{   
}   
Απαντήθηκε 09/12/2008 στις 19:44
πηγή χρήστη

ψήφοι
0

Ένα επιχείρημα που θα μπορούσε κανείς να κάνει για:

foo std :: εγχόρδων ( "bar")?

Είναι ότι κρατά τα πράγματα με τον ίδιο, ακόμη και αν το επιχείρημα μετράνε αλλαγές, δηλαδή:

foo std :: εγχόρδων ( "bar", 5)?

Δεν λειτουργεί με το σύμβολο «=».

Ένα άλλο πράγμα είναι ότι για πολλά αντικείμενα ενός «=» αισθάνεται αφύσικο, για παράδειγμα, ας υποθέσουμε ότι έχετε μια τάξη Array όπου το επιχείρημα δίνει το μήκος:

Array ARR = 5?

Δεν νιώθω καλά, δεδομένου ότι δεν κατασκευάζουμε έναν πίνακα με την τιμή 5, αλλά με μήκος 5:

Array ARR (5)?

αισθάνεται πιο φυσικό, από τη στιγμή που κατασκευάζουμε ένα αντικείμενο με δεδομένη παράμετρο, όχι μόνο αντιγράφοντας μια τιμή.

Απαντήθηκε 09/12/2008 στις 19:36
πηγή χρήστη

ψήφοι
0

Πιστεύω ότι είναι κάτι περισσότερο από μια συνήθεια, πολύ λίγα αντικείμενα θα μπορούσαν να προετοιμαστεί χρησιμοποιώντας =, η σειρά είναι ένας από αυτούς. Είναι επίσης ένας τρόπος για να γίνει αυτό που είπε «χρησιμοποιώντας παρένθεση παντού (ότι η γλώσσα σας επιτρέπει να το χρησιμοποιήσετε)»

Απαντήθηκε 09/12/2008 στις 18:59
πηγή χρήστη

ψήφοι
0

Είναι ένα θέμα του στυλ. Ακόμη και η δήλωση ότι «std :: εγχόρδων =“Foo”? Θα ήταν αναποτελεσματική, διότι συνεπάγεται ένα επιπλέον αντίγραφο» δεν είναι σωστή. Αυτό το «επιπλέον αντίγραφο» αφαιρείται από τον compiler.

Απαντήθηκε 09/12/2008 στις 18:57
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more