Pregunta

Me refiero a que no sea para usarlo cuando sea necesario para funciones, clases, si, mientras, switch, try-catch.

No sabía que podría hacerse como esto hasta que vi esta pregunta SO .

En el enlace anterior, Eli mencionó que "lo usan para plegar su código en secciones lógicas que no entran en una función, clase, bucle, etc. que normalmente se plegaría". "

¿Qué otros usos existen además de los mencionados?

¿Es una buena idea usar llaves para limitar el alcance de sus variables y expandir el alcance solo si es necesario (trabajando en una base de "necesidad de acceso")? ¿O es realmente tonto?

¿Qué te parece usar los ámbitos solo para que puedas usar los mismos nombres de variables en diferentes ámbitos pero en el mismo ámbito más amplio? ¿O es una mejor práctica reutilizar la misma variable (si desea usar el mismo nombre de variable) y ahorrar en la desasignación y la asignación (creo que algunos compiladores pueden optimizar esto)? ¿O es mejor usar nombres de variables diferentes en conjunto?

¿Fue útil?

Solución

Lo hago si estoy usando un recurso que quiero liberar en un momento específico, por ejemplo:

void myfunction()
{
  {
  // Open serial port
     SerialPort port("COM1", 9600);
     port.doTransfer(data);
  } // Serial port gets closed here.

  for(int i = 0; i < data.size(); i++)
     doProcessData(data[i]);
  etc...
}

Otros consejos

No usaría llaves para ese propósito por un par de razones.

  1. Si su función en particular es lo suficientemente grande como para que tenga que realizar varios trucos de alcance, tal vez divida la función en subfunciones más pequeñas.

  2. La introducción de llaves para el alcance para reutilizar nombres de variables solo va a generar confusión y problemas en el código.

Solo mis 2 centavos, pero he visto muchos de estos tipos de cosas en otros materiales de mejores prácticas.

Lo más común " no estándar " El uso del alcance que uso regularmente es utilizar un mutex con alcance.

void MyClass::Somefun()
{
    //do some stuff
    {
        // example imlementation that has a mutex passed into a lock object:
        scopedMutex lockObject(m_mutex); 

        // protected code here

    } // mutex is unlocked here
    // more code here
}

Esto tiene muchos beneficios, pero lo más importante es que el bloqueo siempre se limpiará, incluso si se lanza una excepción en el código protegido.

C ++ :

A veces, es necesario introducir un nivel de refuerzo adicional para reutilizar los nombres de las variables cuando tenga sentido hacerlo:

switch (x) {
    case 0:
        int i = 0;
        foo(i);
        break;
    case 1:
        int i = 1;
        bar(i);
        break;
}

El código de arriba no se compila. Necesitas hacerlo:

switch (x) {
    case 0:
        {
            int i = 0;
            foo(i);
        }
        break;
    case 1:
        {
            int i = 1;
            bar(i);
        }
        break;
}

El uso más común, como han dicho otros, es asegurar que los destructores se ejecuten cuando usted lo desee. También es útil para aclarar un poco el código específico de la plataforma:

#if defined( UNIX )
    if( some unix-specific condition )
#endif
    {
        // This code should always run on Windows but 
        // only if the above condition holds on unix
    }

El código creado para Windows no ve el if, solo las llaves. Esto es mucho más claro que:

#if defined( UNIX )
    if( some unix-specific condition ) {
#endif
        // This code should always run on Windows but 
        // only if the above condition holds on unix
#if defined( UNIX )
    }
#endif

Puede ser una bendición para los generadores de código. Supongamos que tiene un compilador de SQL incorporado (ESQL); es posible que desee convertir una instrucción SQL en un bloque de código que necesite variables locales. Al usar un bloque, puede reutilizar los nombres de las variables fijas una y otra vez, en lugar de tener que crear todas las variables con nombres separados. Por supuesto, eso no es demasiado difícil, pero es más difícil de lo necesario.

Como han dicho otros, esto es bastante común en C ++ debido al lenguaje / patrón RAII (la adquisición de recursos es la inicialización).

Para los programadores de Java (y quizás C #, no lo sé) este será un concepto extraño porque los objetos basados ??en el montón y GC matan a RAII. En mi humilde opinión, ser capaz de poner objetos en la pila es la mayor ventaja de C ++ sobre Java y hace que el código C ++ bien escrito sea MUCHO más limpio que el código Java bien escrito.

Solo lo uso cuando necesito liberar algo por medio de RAII y aún así solo cuando debería liberarse tan pronto como sea posible (por ejemplo, liberar un bloqueo).

Programación en Java Muy a menudo he querido limitar el alcance dentro de un método, pero nunca se me ocurrió usar una etiqueta. Dado que escribo mayúsculas en mis etiquetas cuando las utilizo como objetivo de una pausa, usar un bloque etiquetado de mayúsculas y minúsculas como usted ha sugerido es justo lo que he querido en estas ocasiones.

A menudo, los bloques de código son demasiado cortos para dividirse en un método pequeño y, a menudo, el código en un método de marco (como startup () o shutdown ()) y en realidad es mejor mantener el código unido en un solo método.

Personalmente odio las tiras flotantes / colgantes simples (aunque eso se debe a que somos una tienda de sangría de estilo de banner estricto), y odio el marcador de comentario:

// yuk!
some code
{
scoped code
}
more code

// also yuk!
some code
/* do xyz */ {
    scoped code
    }
some more code

// this I like
some code
DoXyz: {
    scoped code
    }
some more code

Consideramos utilizar " if (true) {" porque la especificación de Java dice específicamente que estos se optimizarán en la compilación (al igual que el contenido completo de un if (falso) - es una función de depuración), pero odié eso en los pocos lugares donde lo probé.

Así que creo que tu idea es buena, en absoluto tonta. Siempre pensé que era la única que quería hacer esto.

Sí, utilizo esta técnica debido a RAII. También utilizo esta técnica en forma simple C , ya que acerca las variables. Por supuesto, debería estar pensando en dividir las funciones aún más.

Una de las cosas que hago que probablemente sea estilísticamente controvertida es poner la llave de apertura en la línea de la declaración o poner un comentario directamente en ella. Quiero reducir la cantidad de espacio vertical desperdiciado. Esto se basa en la recomendación de la Guía de estilo de Google C ++. .

/// c++ code
/// references to boost::test
BOOST_TEST_CASE( curly_brace )
{
  // init
  MyClass instance_to_test( "initial", TestCase::STUFF ); {
    instance_to_test.permutate(42u);
    instance_to_test.rotate_left_face();
    instance_to_test.top_gun();
  }
  { // test check
    const uint8_t kEXP_FAP_BOOST = 240u;
    BOOST_CHECK_EQUAL( instance_to_test.get_fap_boost(), kEXP_FAP_BOOST);
  }
}

Estoy de acuerdo con agartzke. Si siente que necesita segmentar bloques de códigos lógicos más grandes para facilitar la lectura, debe considerar la refactorización para limpiar miembros ocupados y desordenados.

Tiene su lugar, pero no creo que hacerlo para que $ foo pueda ser una variable aquí y una variable diferente allí , dentro de la misma función u otro (lógico, en lugar de léxico) es una buena idea. A pesar de que el compilador puede entender eso perfectamente, parece muy probable que dificulte la vida a los humanos que intentan leer el código.

La empresa en la que estoy trabajando tiene una política de análisis estático para mantener las declaraciones de variables locales cerca del comienzo de una función. Muchas veces, el uso es muchas líneas después de la primera línea de una función, por lo que no puedo ver la declaración y la primera referencia al mismo tiempo en la pantalla. Lo que hago para "burlar" la política es mantener la declaración cerca de la referencia, pero proporcionar un alcance adicional mediante llaves. Sin embargo, aumenta la sangría, y algunos pueden argumentar que hace que el código sea más feo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top