2009-02-10 14 views
63

He estado utilizando construcciones C++ más "modernas" por un tiempo, pero superficialmente y no en todas partes. Estoy buscando proyectos de código abierto para estudiar que son buenos ejemplos del uso moderno de C++ y STL.Ejemplos de "C++ moderno" en acción?

Cosas como las que se sugieren en "Effective STL" de Meyer, como tratar de evitar los bucles for y reemplazarlos por construcciones más funcionales, usando boost :: bind y boost :: function, etc. Estos aún se sienten un poco antinaturales para mí, y cuando tengo que hacer algo rápido y trabajando, tiendo a volver a libc y string.h (puedes agarrar mi strtok cuando lo levantas de mis manos frías y muertas).

Sin embargo, también he tenido la experiencia positiva de encontrar lo que sería un cambio drástico simplificado porque he usado estos constructos, o puedo implementar algo con unas pocas líneas de código, porque tenía el derecho operadores y funtores por ahí. Además, recientemente he estado prestando más atención a la concurrencia, por lo que esto se está volviendo aún más importante para mí.

¿Puede recomendar algunos ejemplos de proyectos de código abierto bien escritos que hacen un uso intensivo de la STL y otras técnicas modernas de C++ que podría estudiar? Estoy particularmente interesado en el código de la aplicación, explorar las fuentes de Boost ha sido útil, pero es por necesidad muy general porque es un código de biblioteca.

Me interesan los proyectos de tamaño mediano a grande, al menos algunas decenas de miles de líneas. Es bastante fácil encontrar ejemplos que tienen cientos de líneas, pero eso no es demasiado útil.

+1

¿Puedo quita tu strtok() pero dale strtok_r() a cambio? Es seguro para subprocesos y reentrante. –

+0

Renuncié a strtok cuando escribí una clase de tokenizer que devolvía un const_iterator de su método begin() para permitirme repetir los tokens. –

+3

Boost's String Algo, Regex, Spirit, Xpressive (e incluso Tokenizer si tienes mala suerte) comerán 'strok()' alive. :) – jfs

Respuesta

11

Aquí, se encuentran varios ejemplos interesantes de cómo Boost está en uso en proyectos de código abierto:
http://www.boost.org/users/uses_open.html

+1

¡Eso es genial! Siempre echo de menos los lugares obvios para mirar ... – joeld

+1

Prefiero haber encontrado un ejemplo excelente, estos aumentos de uso y C++ modernos en grados variables y menores, pero esta fue la mejor fuente de ejemplos del mundo real (no solo fragmentos) que pude encontrar – joeld

+1

Las respuestas que solo contienen enlaces son [consideradas malas prácticas] (http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers). Resuma el contenido aquí (no copie/pegue) para que la respuesta pueda ser independiente. Si no lo hace, corre el riesgo de que su respuesta sea eliminada, especialmente si el enlace alguna vez muere. –

4

no estoy seguro sobre el "bien escrito", pero hay algunas cosas por ahí como Hypertable y KFS que son software a nivel de sistema que ambos utilizan Boost y STL ampliamente.

He escuchado algunas cosas sobre OpenOffice y Google Chrome pero no he revisado su código fuente para saber con cuánta precisión usan STL. Eché un vistazo al KDE pero no necesariamente llamaría a ese C++ moderno. Puedo decirte que un código en el que estoy trabajando está haciendo mucho C++ moderno, pero desafortunadamente no es de código abierto, aunque creo que es cuestión de tiempo y paciencia sacar el enfoque moderno de C++ y tener más proyectos de código abierto. adoptando los modismos.

+0

Gracias, investigaré esos. Esa también ha sido mi sensación de que el C++ "moderno" se usa mucho en proyectos internos, pero no tiene un uso "público" mucho más visible. – joeld

+0

me gusta KDE, creo que es muy moderno. C++, creo, usando el modismo pimpl con mucha fuerza. –

15

En realidad, eché un vistazo a Google Chrome y lo recomendaría. La codificación de Google C++ guidelines es un buen andamio para proyectos grandes. También son utilizados/adoptados en nuestro equipo. Además, estoy muy contento de que proporcionen sus marcos C++ mocking y testing como proyectos de código abierto. Muy útil para grandes proyectos en los que se pierden muchas de las agradables pruebas del mundo Java/Managed.

+7

Miré a través de él, excelente código, gran ejemplo pero no muy estilo "Modern C++". – joeld

+6

Las pautas de codificación de Google son antiguas y no son un buen ejemplo del estilo moderno de C++. –

+0

Repara el enlace a "directrices", por favor. – nbro

23

Meyers está bien, sin embargo, si realmente quiere empujar a sí mismo, usted tiene que leer:

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

Se dejará su mente. Lo que aprendes en el libro describe el Loki library.

Uno de mis favoritos es el conversiones-int a tipo:

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

Lo he utilizado en el pasado para mi biblioteca de serialización XML C++ para la pre-asignación de vectores <> 's antes de cargarlos con datos:

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

Observe las especializaciones privadas mencionadas anteriormente. Bueno, si miras con atención, una llama a reserva(), y la otra no. Esta es una especialización de plantilla que usa un bool como tipo.

que a su vez es utilizado por:

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

Para hacer las cosas simples en código C++ de los usuarios, que añade una gran cantidad de definiciones de ayuda:

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

Así que en su código que había usar algo como:

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

O para los vectores:

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

De todos modos, voy a dejar de hablar sobre ... Eso es simplemente poner la plantilla de Int2Type <> simple para un buen uso. Hay muchas cosas ingeniosas como hacer que el compilador calcule un montón de cosas de antemano mediante el uso inteligente de enumeraciones. Es un libro realmente increíble.

+1

¿Por qué no escribir una función de reserva de plantilla que no hace nada, y luego una especialización para std :: vector que llama a reservar en ella? De esta forma, la persona que llama no tiene que pasar un bool para controlar si se debe llamar a la reserva. Simplemente lo encuentra basado en el tipo de contenedor. –

+0

Sí, me encanta ese libro. Ese es exactamente el tipo de cosas que estoy tratando de aplicar en una escala mayor. – joeld

+3

Tengo un desbordamiento de la mente. ¿Este código deja de verse como "solo escritura" después de leer el libro mencionado anteriormente? – Muxecoid

5

realmente no proyectos, pero aquí hay un par de fragmentos:

uso Muestra de impulso :: hilo/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 :: copia, std :: transforman, 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, " ")); 
} 

El fragmento leerá desde el usuario la entrada de un conjunto de cadenas en un vector. Luego, para cada cadena en el vector, se convertirá en mayúscula y finalmente dará salida al resultado.

Nuestras aplicaciones hacen un uso intensivo de las señales de impulso :: :: e impulsar la función de desacoplar las clases en las que no es el momento crítico, principalmente en las clases de interfaz de usuario:

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

Cada panel tiene información sobre otros paneles. El código que une los paneles tiene el conocimiento del flujo (para editar un panel de detalles de contactos de contacto, notificar la finalización de la edición al panel de la lista de contactos). Además, hay una señal global para notificar a los paneles sobre las actualizaciones del modelo subyacente.

Esto es especialmente útil cuando necesita escribir código de prueba. No es necesario implementar clases simuladas para reemplazar el código de trabajo para la prueba. Las pruebas simplemente crean una instancia de la clase y conectan las funciones/señales al código de prueba sin que la clase probada advierta, siguiendo el principio de mínima intrusión durante las pruebas.

+0

'boost :: to_upper (s)' podría reemplazar 'transform (s.begin(), s.end(), s.begin(), toupper)'. – jfs

+0

'for_each (v.begin(), v.end(), cout << _1 <<" ");' o 'foreach (cadena s, v) cout << s <<" ";' podría reemplazar 'std :: copy (v.begin(), v.end(), std :: ostream_iterator (std :: cout, "")); ' – jfs

+0

cout << _1 <<" "- requiere boost :: lambda, que Lo he intentado, pero no me siento lo suficientemente cómodo como para escribir un fragmento de la parte superior de mi cabeza. No sabía sobre boost :: to_upper (s), gracias. –

3

Adobe ha publicado una gran cantidad de C moderna ++ código fuente abierto en el último par de años, que es probablemente vale la pena ver:

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

que creen que su biblioteca GIL cualquiera haya sido, o está en proceso de ser agregado a Boost. su STLab contiene una tonelada de funcionalidad que, por lo que he visto, es muy limpia y muy similar a STL.

+0

Intenté usar GIL hace un año y me pareció realmente increíble desde el punto de vista del diseño, pero poco realista para el trabajo en el mundo real. Los tiempos de compilación fueron malos, fue increíblemente difícil de depurar, y tener que tener any_image <> type fue incómodo. Lo estoy vigilando para el futuro aunque. – joeld

2

Aquí hay un fragmento de concatenar vector de cadenas en una cadena:

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