tutorial smart remix programador online espaƱol curso c++ coding-style lambda c++11

c++ - remix - smart contracts ethereum



C++ 0x estilo de codificaciĆ³n lambdas (5)

¡Puedo ver una nueva norma de codificación aquí! ;)

Esto es un poco artificial, pero solo para resaltar una "ventaja" de ser explícito, considere lo siguiente:

void foo (std::vector<int> v, int x1) { int sum = 0; std::for_each (v.begin () , v.end () , [&](int xl) { sum += x1; } }

Ahora, he elegido deliberadamente nombres pobres, etc. para esto, pero es solo para ilustrar el punto. Si usamos una lista de captura explícita, el código anterior no se compilaría, pero actualmente lo hará.

En un entorno muy estricto (seguridad crítica) puedo ver una regla como esta que forma parte del estándar de codificación.

Me pregunto cómo la gente está utilizando C ++ 0x lambdas, en términos de estilo de codificación. La pregunta más interesante es qué tan profundo debe ser al escribir la lista de captura. Por un lado, el lenguaje permite enumerar explícitamente las variables capturadas, y por "explícitamente es mejor que una regla implícita", por lo tanto, tendría sentido hacer una lista exhaustiva para establecer claramente la intención. P.ej:

int sum; std::for_each(xs.begin(), xs.end(), [&sum](int x) { sum += x });

Otro argumento para esto es que, dado que la vida útil de los locales capturados por referencia no cambia solo porque se capturan (y por lo tanto, un lambda puede fácilmente hacer referencia a un local cuya vida útil ha finalizado), haciendo que la captura sea explícita ayuda a reducir tales errores y rastrearlos.

Por otro lado, el idioma también proporciona deliberadamente un atajo para la captura automática de todos los locales a los que se hace referencia, por lo que claramente está destinado a ser utilizado. Y se podría afirmar que para un ejemplo como el de arriba, es muy claro lo que sucede incluso con la captura automática, y la vida útil de Lambda es tal que no sobrevivirá al alcance circundante, por lo que no hay razón para no usarlo:

int sum; std::for_each(xs.begin(), xs.end(), [&](int x) { sum += x });

Obviamente, esto no tiene que ser todo o nada, pero tiene que haber alguna razón para decidir cuándo capturar automáticamente y cuándo capturar explícitamente. ¿Alguna idea?

Otra pregunta en el mismo sentido es cuándo usar la captura por copia - [=] , y cuándo usar la captura por referencia - [&] . La captura por copia es obviamente más segura porque no hay problemas de por vida, por lo que se podría argumentar que se debe usar de forma predeterminada cuando no sea necesario mutar el valor capturado (o ver los cambios realizados desde otro lugar), y capturar la referencia por referencia debe tratarse como optimización (potencialmente prematura) en tales casos, para ser aplicada solo cuando claramente haga una diferencia.

Por otro lado, la captura por referencia es casi siempre más rápida (especialmente porque a menudo se puede optimizar para una copia, si esta última es más rápida, para tipos pequeños y funciones de plantilla en línea como la mayoría de los algoritmos STL), y es seguro si lambda nunca sobrevive a su alcance (que también es el caso de todos los algoritmos STL), por lo que la captura por referencia predeterminada en este caso es una optimización trivial e inofensiva que no daña.

¿Cuáles son tus pensamientos?



Iría con listas de captura explícitas cuando sea conveniente, cuando quiera capturar muchas variables (probablemente esté haciendo algo mal y) puede usar la lista de captura de todos [&] .

Mi opinión es que las listas de captura explícitas son lo ideal y las variantes implícitas deben evitarse y solo están ahí para que las personas no tengan que escribir resmas de código cuando realmente son necesarias.


Mi instinto inicial fue que la captura por valor ofrece más o menos lo mismo que las clases internas anónimas de Java, que son una cantidad conocida. Pero en lugar de utilizar el truco de matriz de tamaño 1 cuando desea que el ámbito de cierre sea mutable, puede capturar por referencia en su lugar. Entonces es su responsabilidad limitar la duración de la lambda dentro del alcance del referendo.

En la práctica, estoy de acuerdo con usted en que la captura por referencia debe ser la predeterminada cuando se trata de algoritmos, que espero sean la mayoría de los usos. Un uso común para las clases internas anónimas en Java son los escuchas. Hay menos interfaces de estilo de escucha que se pueden ver en C ++ para comenzar, por lo que es una necesidad menor, pero aún existe. Podría ser mejor atenerse estrictamente a la captura por valor en ese tipo de caso, para evitar la oportunidad de error. ¿La captura por valor de un shared_ptr será un gran lenguaje, tal vez?

Sin embargo, no he usado lambdas todavía, así que es posible que me haya perdido algo enorme.


Nunca he oído hablar de la regla de "explícito es mejor que una regla implícita", y no estoy de acuerdo con ella. Hay casos donde es cierto, por supuesto, pero también hay muchos casos donde no lo es. Es por eso que 0x es agregar inferencia de tipo con la palabra clave auto después de todo. (y por qué los parámetros de la plantilla de función ya se deducen cuando es posible) Hay muchos casos donde es preferible lo implícito.

Realmente no he usado las lambdas de C ++ todavía (aparte de hurgarme con la beta VC10), pero la última vez la usé

std::for_each(xs.begin(), xs.end(), [&](int x) { sum += x });

Mi razonamiento? ¿Por qué no hacerlo? Es conveniente. Funciona. Y es más fácil de mantener. No tengo que actualizar la lista de captura cuando modifico el cuerpo de la lambda. ¿Por qué debería ser explícito sobre algo que el compilador sabe mejor que yo? El compilador puede averiguar la lista de captura en función de lo que realmente se utiliza.

¿En cuanto a la captura por referencia vs valor? Aplicaría las mismas reglas que hago para las funciones regulares. Si necesitas semántica de referencia, captura por referencia. Si necesitas copiar la semántica, haz eso. Si cualquiera de los dos servirá, prefiera el valor para tipos pequeños y haga referencia si la copia es costosa.

No parece diferente de la elección que tiene que hacer al diseñar una función regular.

Probablemente debería leer las especificaciones de las lambdas, pero ¿no es la razón principal de las listas de captura explícitas para poder capturar algunas variables por valor y otras por referencia?