2. MADRID · NOV 27-28 · 2015
int foo;
foo es un entero
3. MADRID · NOV 27-28 · 2015
int* foo;
foo es un puntero a un entero
4. MADRID · NOV 27-28 · 2015
char *(*(**foo [][8])())[];
foo es un array de arrays de 8 punteros a función retornando un
puntero a un array de punteros a char
8. MADRID · NOV 27-28 · 2015
C++ no es un “mejor C”
Olvida las “buenas prácticas” de C: no tienen porque ser
“buenas prácticas” de C++
No uses const char* para cadenas. Usa std::string
Usa la librería estándard de C++, “olvida” la de C
(strcpy, printf, ...)
No uses arrays directamente. Usa las clases de la
librería de C++ (std::vector, std::map,...) en su lugar
Usa referencias antes que punteros
9. MADRID · NOV 27-28 · 2015
C++98... C++11... C++14
C++98 es el estándard más usado de C++. Con el que
(casi) todos aprendimos, vaya :P
El lenguaje ha evolucionado mucho. El estándard
C++0x se concebió para estandarizar muchas de esas
evoluciones.
C++0x terminó siendo C++11
C++14 es una revisión menor de C++11
10. Modern C++
Ámbito de pila antes de ámbito de heap
Smart pointers antes que punteros
“desnudos”
Contenedores estándard antes que
propios
Algoritmos estándard antes que propios
Excepciones para reportar errores
Expresiones lambda
Range-based loops en lugar de bucles
normales
...
11. MADRID · NOV 27-28 · 2015
Classical C++...
circle* p = new circle();
shape** shapes = load_shapes_classic();
for (int idx = 0; idx < 10; idx++) {
cout << "Shape found " << shapes[idx]->name().c_str() << "n";
}
// Need to delete all shapes
for (int idx = 0; idx < 10; idx++) {
delete shapes[idx];
}
delete shapes;
delete p;
12. MADRID · NOV 27-28 · 2015
Modern C++
auto p = make_shared<circle>();
auto v = load_shapes_modern();
for_each(v.begin(), v.end(), [&](const shared_ptr<shape>& s) {
cout << "Shape found " << s->name().c_str() << "n";
});
13. MADRID · NOV 27-28 · 2015
Inferencia de tipos
Palabra clave auto declara el tipo de una variable en
función de su expresión
auto i = 10;
auto v = vector<int>();
...
14. MADRID · NOV 27-28 · 2015
auto
Muy útil en aquellos casos en que el tipo es realmente
complicado o complejo de saber
auto v = std::vector<int>();
// antes:
std::vector<int>::iterator i = v.begin();
// ahora:
auto i = v.begin();
15. MADRID · NOV 27-28 · 2015
auto
Necesario en aquellos casos en que el tipo es
imposible de saber por el desarrollador (pero sí por el
compilador en tiempo de compilación):
template<typename T, typename S>
void foo(T lhs, S rhs) {
????? prod = lhs * rhs;
// code...
}
16. MADRID · NOV 27-28 · 2015
decltype
Similar a auto en su concepción, pero decltype deduce un tipo en
base a una expresión pasada a decltype:
decltype(10) a; // a es int
decltype(2*3.0) b; // b es double
Necesario cuando el tipo de retorno de una función no es
conocido por el desarrollador (pero sí por el compilador en tiempo
de compilación)
17. MADRID · NOV 27-28 · 2015
decltype
¿Cual es el tipo de retorno de la función? Dependerá de
los tipos T y S resueltos en compilación.
template<typename T, typename S>
???? foo(T lhs, S rhs) {
auto prod = lhs * rhs;
return prod;
}
18. MADRID · NOV 27-28 · 2015
decltype
Problema: La idea es correcta pero no compila porque
lhs y rhs no están definidos al usar decltype
template<typename T, typename S>
decltype(lhs * rhs) foo(T lhs, S rhs) {
auto prod = lhs * rhs;
return prod;
}
19. MADRID · NOV 27-28 · 2015
trailing return type syntax
Se puede especificar el tipo del valor de retorno de
una función al final de la firma, usando ->
int sum(int a, int b) {...}
auto sum (int a, int b) -> int {...}
20. MADRID · NOV 27-28 · 2015
decltype
Ahora lhs y rhs estan definidos al usar decltype
template<typename T, typename S>
auto foo(T lhs, S rhs)-> decltype(lhs * rhs) {
auto prod = lhs * rhs;
return prod;
}
21. MADRID · NOV 27-28 · 2015
Referencias
Usa referencias antes que punteros siempre que sea
posible.
Las referencias siempre apuntan a un objeto siendo
mucho más seguras que un puntero
Muchas de las cosas que hacemos con punteros
pueden ser resueltas con referencias.
22. MADRID · NOV 27-28 · 2015
Gestión de la memoria
1. La diferencia fundamental entre new y delete por una parte, y malloc() y free()
por otra es que los primeros crean y destruyen objetos, mientras que los
segundos se limitan a reservar y liberar zonas de memoria
2. Al utilizar delete (lo mismo sucede con free()), se libera la zona de memoria a la
que apunta, pero sin borrar el propio puntero. Si se manda liberar lo apuntado por
un puntero nulo no pasa nada especial y el programa no libera memoria. Sin
embargo si se ordena liberar dos veces lo apuntado por un puntero las
consecuencias son imprevisibles y puede que incluso catastróficas, por lo
que es importante evitar este tipo de errores
http://mat21.etsii.upm.es/ayudainf/aprendainf/Cpp/manualcpp.pdf (pags 30,31)
23. MADRID · NOV 27-28 · 2015
Gestión de la memoria
Si usas new y delete para gestionar la memoria... lo
estás haciendo mal.
Es posible conseguir en C++, liberación automática de
memoria, de forma determinista y sin apenas esfuerzo.
Resource Acquisition Is Initialization
24. MADRID · NOV 27-28 · 2015
Gestión de la memoria - RAII
std::shared_ptr<T>
Encapsula el puntero a un objeto de
tipo T y un contador de
referencias asociado, compartido
por todos los shared_ptr que
apunten al mismo objeto
25. MADRID · NOV 27-28 · 2015
Gestión de la memoria - RAII
std::unique_ptr<T>
Objeto que mantiene la propiedad exclusiva de un
puntero a un objeto de tipo T.
Un unique_ptr no puede ser copiado, no pueden haber
dos unique_ptr apuntando al mismo objeto.
26. MADRID · NOV 27-28 · 2015
RAII
RAII se aplica no solo a memoria si no en general en
cualquier tipo de recurso:
class file
{
public:
file( const char* filename ) : m_file_handle(std::fopen(filename, "w+"))
{ }
~file()
{
std::fclose(m_file_handle) ;
}
private:
std::FILE* m_file_handle ;
file( const file & ) ;
file & operator=( const file & ) ;
} ;
void example_with_RAII()
{
// open file (acquire resource)
file logfile("logfile.txt");
// Use the resource. When exiting by going out
// of scope
// for any reason (including exceptions) file will
// be closed. No action needed to release the
// resource.
}
27. MADRID · NOV 27-28 · 2015
Expresiones lambda
Permiten definir closures de forma muy sencilla,
manteniendo en todo momento el control de qué
variables se quieren capturar.
[](int i)->int {return i * 2; };
Captura de variables Parámetros
Tipo retorno
Código
28. MADRID · NOV 27-28 · 2015
Expresiones lambda
Una expresión lambda... ¿Devuelve un puntero a
función?
¡NO! Devuelve un objeto que tiene operator() definido
29. MADRID · NOV 27-28 · 2015
Tipo de expresión lambda
Una expresión lambda tiene un tipo propio y único
generado por el compilador, pero que es convertible al
tipo function<T> siendo T la firma de la función.
P. ej. El tipo function<R(T,S)> representa una lambda
que tiene dos parámetros de tipo T y S y que devuelve
un valor de tipo T
30. MADRID · NOV 27-28 · 2015
Expresiones lambda template
Una expresión lambda puede tener parámetros
template
La palabra clave auto indica que el tipo del parámetro
es autodeducido
auto lambda_sum = [](auto x, auto y) {
return x + y;
};
¡Esto es un template no
inferencia de tipos!
31. MADRID · NOV 27-28 · 2015
¿Hay más?
Por supuesto.... Hay mucho más.
C++11 incluye muchas otras características:
1. Move semantics (r-value references)
2. override/final
3. type traits
4. Funciones deleted y defaulted
5. Variadic templates
6. Más...
32. MADRID · NOV 27-28 · 2015
¿Donde seguir?
http://www.stroustrup.com/C++11FAQ.html
https://en.wikipedia.org/wiki/C%2B%2B11
https://en.wikipedia.org/wiki/C%2B%2B14
https://isocpp.org/wiki/faq/cpp11-language
https://isocpp.org/wiki/faq/cpp14-language
The C++ standard book:
http://www.amazon.es/The-Programming-Language-
Bjarne-Stroustrup/dp/0321958322/
33. MADRID · NOV 27-28 · 2015
Gracias!!!!!
Eduard Tomàs
etomas@gmail.com
@eiximenis
http://geeks.ms/blogs/etomas