2009-02-10 7 views
63

Ich benutze seit einiger Zeit mehr "moderne" C++ - Konstrukte, aber irgendwie oberflächlich und nicht überall. Ich bin auf der Suche nach Open-Source-Projekten zu studieren, die gute Beispiele für moderne C++ - und STL-Nutzung sind.Beispiele für "modernes C++" in Aktion?

Dinge, wie in Meyers "Effective STL" vorgeschlagen, wie zum Beispiel for Schleifen zu vermeiden und sie durch funktionellere Konstrukte zu ersetzen, mit boost :: bind und boost :: -Funktion, etc. Diese fühlen sich immer noch ein wenig unnatürlich zu mir, und wenn ich etwas schnell erledigen und arbeiten muss, tendiere ich dazu zurück zu libc und string.h (du kannst meine strtok haben, wenn du sie aus meinen kalten, toten Händen hebst).

Allerdings hatte ich auch die positive Erfahrung zu finden, was eine drastische Änderung vereinfacht hätte, weil ich diese Konstrukte verwendet habe oder etwas mit nur ein paar Zeilen Code implementieren konnte, weil ich das Recht hatte Operatoren und Funktoren herumliegen. Außerdem habe ich in letzter Zeit dem Nebeneinander mehr Aufmerksamkeit geschenkt, und das wird für mich immer wichtiger.

Können Sie einige Beispiele für gut geschriebene Open-Source-Projekte empfehlen, die stark von der STL und anderen modernen C++ - Techniken Gebrauch machen, die ich studieren könnte? Ich bin besonders an Anwendungscode interessiert, das Durchsuchen der Boost-Quellen war hilfreich, aber es ist notwendigerweise sehr allgemein, weil es Bibliothekscode ist.

Ich interessiere mich für mittelgroße bis größere Projekte, mindestens einige zehntausend Linien. Es ist ziemlich einfach, Beispiele zu finden, die ein paar hundert Zeilen lang sind, aber das ist nicht sehr hilfreich.

+1

Kann ich nimm dir deine strtok() weg aber gibst du strtok_r() zurück? Es ist Thread-Safe und Reentrant. –

+0

Ich gab strtok auf, als ich eine Tokenizer-Klasse schrieb, die einen const_iterator von ihrer begin() -Methode zurückgab, um mich durch die Token zu iterieren. –

+3

Boost's String Algo, Regex, Spirit, Xpressive (und selbst Tokenizer, wenn du unglücklich bist) essen 'strok()' am Leben. :) – jfs

Antwort

11

Hier finden Sie einige interessante Beispiele, wie Boost-in Open-Source-Projekten verwendet wird:
http://www.boost.org/users/uses_open.html

+1

Das ist großartig! Ich vermisse immer die offensichtlichen Plätze, um zu schauen. – joeld

+1

Ich hätte lieber ein ausgezeichnetes Beispiel gefunden, diese verwenden Boost und modernes C++ zu unterschiedlichen und geringeren Graden, aber dies war die beste Quelle von realen Beispielen (nicht nur Schnipsel) das konnte ich finden. – joeld

+1

Antworten, die nur Links enthalten, werden als "schlechte Praxis" betrachtet (http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really- good-answers). Bitte fassen Sie den Inhalt hier zusammen (nicht kopieren/einfügen), damit die Antwort für sich alleine stehen kann. Wenn Sie nicht Gefahr laufen, dass Ihre Antwort entfernt wird, besonders wenn die Verbindung jemals stirbt. –

4

Ich bin mir nicht sicher über "gut geschrieben", aber es gibt ein paar Dinge wie Hypertable und KFS, die System-Level-Software sind, die beide Boost und STL ausgiebig verwenden.

Ich habe einiges über OpenOffice und Google Chrome gehört, aber ich habe nicht ihren Quellcode angeschaut, um zu wissen, wie genau sie die STL verwenden. Ich habe einen Blick auf KDE geworfen, aber ich würde nicht unbedingt das moderne C++ nennen. Ich kann Ihnen sagen, dass ein Teil des Codes, an dem ich arbeite, viel modernes C++ tut, aber leider nicht Open Source - obwohl ich denke, dass es nur eine Frage von Zeit und Geduld ist, den modernen C++ Ansatz zu nutzen und mehr Open Source Projekte zu haben die Idiome übernehmen.

+0

Danke, ich schaue mir die an. Das war auch mein Gefühl, dass "modernes" C++ sehr oft in internen Projekten verwendet wird, aber nicht viel mehr "öffentlich" genutzt wird. – joeld

+0

ich mag KDE es ist wirklich modern C++ ich denke, mit dem Pimpl Idiom sehr stark. –

15

Eigentlich hatte ich einen Blick in Google Chrome und würde es empfehlen. Googles C++ - Codierung guidelines ist ein gutes Gerüst für ein großes Projekt. Sie werden auch in unserem Team verwendet. Außerdem bin ich sehr froh, dass sie ihre C++ mocking und testing Frameworks als Open-Source-Projekte zur Verfügung stellen. Sehr praktisch für große Projekte, bei denen Sie eine Menge der netten Test-Sachen aus der Java/Managed-Welt vermissen.

+7

Ich schaute durch, toller Code, tolles Beispiel, aber nicht sehr "Modern C++" -Stil. – joeld

+6

Googles Codierungsrichtlinien sind alt und sie sind kein gutes Beispiel für den modernen C++ - Stil. –

+0

Bitte den Link zu "Richtlinien" korrigieren. – nbro

23

Meyers ist in Ordnung, aber wenn Sie wirklich selbst wollen drücken, Sie zu lesen:

Andrei Alexandrescu - Modern C++ Design: Generic Programming and Design Patterns Applied

Es wird blow your Mind. Was Sie in dem Buch lernen, beschreibt die Loki library.

Einer meiner Favoriten ist die int-to-Typkonvertierungen:

template <int v> 
struct Int2Type 
{ 
    enum { value = v }; 
}; 

Ich habe es in der Vergangenheit für meine C++ XML-Serialisierung Bibliothek für Pre-Zuweisung Vektor <> 's vor dem Laden sie verwendet mit Daten:

// We want to call reserve on STL containers that provide that function, 
// namely std::vector. 
// However, we would get a compiler error if we tried to call reserve on 
// an STL container that 
// did not provide this function. This is the solution. 
template <bool b, class T> 
class CReserve 
{ 
public: 
    static void reserve(T &lst, const int &n) 
    { reserve(lst, n, Loki::Int2Type<b>()); } 

private: 
    static void reserve(T &lst, const int &n, Loki::Int2Type<true>) 
    { lst.reserve(n); } 

    static void reserve(T &lst, const int &n, Loki::Int2Type<false>) 
    { (void)lst; (void)n; } 
}; 

Beachten Sie die privaten Spezialisierungen oben. Nun, wenn Sie genau hinsehen, ruft man reserve(), und das andere nicht. Dies ist eine Template-Spezialisierung, bei der ein Bool als Typ verwendet wird.

wiederum die durch verwendet wird:

template <bool bCallReserve, class T> 
bool STLSerializeClassType(MSXML::IXMLDOMNodePtr pCurNode, T &lst, 
          CXmlArchive &archive, const char *name) 
{ 
    if(archive.IsStoring()) 
    { 
     ... 
    } else { 
     lst.clear(); 

     T::size_type nCount(0); 
     XML_ELEMENT(nCount); 

     CReserve<bCallReserve, T>::reserve(lst, nCount); 

     while(nCount--) 
     { 
      T::value_type temp; 
      temp.SerializeXml(archive, pCurNode); 
      lst.push_back(temp); 
     } 
    } 
} 

Um die Dinge einfach in den Benutzern C++ Code zu machen, habe ich eine Menge Helfer Definitionen:

#define SERIALIZE_XML_STL_CLASS(list_name, bCallReserve) \ 
(HS::STLSerializeClassType<(bCallReserve)> 
    (pCurNode, (list_name), archive, (#list_name)) 
) 

Sie also in Ihrem Code würde verwenden Sie so etwas wie:

std::list<CFred> fredList; 
SERIALIZE_XML_STL_CLASS(fredList, false); 

Oder für Vektoren:

vector<CFred> fredList; 
SERIALIZE_XML_STL_CLASS(fredList, true); 

Wie auch immer, ich werde aufhören zu wittern auf ... Das ist nur die einfache Int2Type <> Vorlage zu nutzen. Es gibt viele clevere Sachen, wie den Compiler dazu zu bringen, eine Menge Dinge vorher durch geschickte Verwendung von Enums zu berechnen. Es ist ein wirklich tolles Buch.

+1

Warum nicht eine Vorlage Reserve-Funktion schreiben, die nichts tut, und dann eine Spezialisierung für Std :: Vektor, die Reserve auf sie ruft? Auf diese Weise muss der Aufrufer kein Bool übergeben, um zu steuern, ob Reserve aufgerufen werden soll. Es wird nur anhand des Containertyps ermittelt. –

+0

Ja, ich liebe dieses Buch. Das ist genau die Art von Sachen, die ich versuche, in einem größeren Maßstab anzuwenden. – joeld

+3

Ich habe einen Gedankenüberfluss. Sieht dieser Code nach dem Lesen des oben erwähnten Buches nicht mehr wie "schreib nur" aus? – Muxecoid

5

Nicht wirklich Projekte, hier aber ein paar Schnipsel sind:

Beispiel Verwendung von boost :: thread/boost :: bind:

class X { void expensive_operation(int argument); }; 

int main() 
{ 
    X x; 
    boost::thread thr(boost::bind(&X::expensive_operation, &x, 1000)); 
    std::cout << "Thread is processing..." << std::endl; 
    thr.join(); 
} 

std :: copy, std :: transformieren, BOOST_FOREACH:

int main() 
{ 
    std::vector<std::string> v; 
    std::copy(std::istream_iterator<std::string>(std::cin), 
       std::istream_iterator<std::string>(), std::back_inserter(v)); 
    BOOST_FOREACH(std::string & s, v) 
    { 
     transform(s.begin(), s.end(), s.begin(), toupper); 
    } 
    std::copy(v.begin(), v.end(), 
       std::ostream_iterator<std::string>(std::cout, " ")); 
} 

Das Snippet wird von Benutzereingabe eine Reihe von Zeichenfolgen in einen Vektor lesen. Dann wird für jeden String im Vektor in Großbuchstaben konvertiert und schließlich das Ergebnis ausgegeben.

Unsere Anwendungen machen starken Gebrauch von boost :: Signale und boost :: Funktionsklassen zu entkoppeln, wo es nicht zeitkritisch ist, vor allem in der UI-Klassen:

class ContactDetailPanel; 
class ContactListPanel { 
public: 
    void update(); 
    void edit_completed(bool change); 
    boost::function< void (Contact &) >& edit_contact();  
}; 
int main() 
{ 
    ContactListPanel clp; 
    ContactDetailPanel cdp; 

    clp.edit_contact() = boost::bind(&ContactDetailPanel::edit, &cdp, _1); 
    cdp.edit_completed() = boost::bind(&ContactListPanel::edit_completed, &clp, _1); 
    ui::signal_update().connect(boost::bind(&ContactListPanel::update, &clp));  
} 

Jede Platte keine Informationen über andere Platten hat. Der Code, der die Panels miteinander verbindet, verfügt über das Flow-Wissen (zum Bearbeiten eines Kontaktzugriffsdetailbereichs, um Edit Completion dem Kontaktlistenbereich mitzuteilen). Außerdem gibt es ein globales Signal, um Panels über Aktualisierungen des zugrunde liegenden Modells zu benachrichtigen.

Dies ist besonders hilfreich, wenn Sie Testcode schreiben müssen. Es ist nicht erforderlich, Scheinklassen zu implementieren, um Arbeitscode zum Testen zu ersetzen. Tests instanziieren die Klasse und verbinden die Funktionen/Signale mit dem Testcode, ohne dass die getestete Klasse dies bemerkt, wobei sie dem Prinzip des geringsten Eindringens während Tests folgt.

+0

'boost :: to_upper (s)' könnte 'transform ersetzen (s.begin(), s.end(), s.begin(), toupper)'. – jfs

+0

'for_each (v.begin(), v.end(), cout << _1 <<" ");' oder 'foreach (Zeichenkette s, v) cout << s <<" ";" könnte 'Std ersetzen :: copy (v.begin(), v.end(), std :: ostream_iterator (std :: cout, "")); ' – jfs

+0

cout << _1 <<" "- erfordert boost :: lambda, was Ich habe es versucht, fühle mich aber nicht wohl genug, um einen Ausschnitt aus meinem Kopf zu schreiben. Ich wusste nichts über boost :: to_upper (s), danke. –

3

Adobe viel moderner C in den letzten paar Jahren ++ Open-Source-Code veröffentlicht, die Überprüfung wahrscheinlich wert ist out:

http://opensource.adobe.com/wiki/display/site/Home

ich ihre GIL Bibliothek glauben entweder ist, oder wird zu Boost hinzugefügt. ihre STLab enthält eine Tonne Funktionalität zu, die, was ich gesehen habe, ist sehr sauber und sehr viel STL-Stil.

+0

Ich habe vor etwa einem Jahr versucht, GIL zu verwenden, und ich fand es vom Design her wirklich erstaunlich, aber unrealistisch für die Arbeit in der realen Welt. Die Kompilierungszeiten waren schlecht, es war erstaunlich schwierig zu debuggen, und es war unangenehm, any_image <> zu schreiben. Ich behalte es für die Zukunft im Auge. – joeld

2

Hier ist ein Ausschnitt Vektor von Strings in einer Zeichenfolge verketten:

vector<string> vecstr; 
vecstr.push_back("abc"); 
vecstr.push_back("efg"); // etc. 
string concat = accumulate(vecstr.begin(), vecstr.end(), string(""));