Diapositivas de la formación de C++ que imparto de vez en cuando. No están totalmente actualizadas, pero cubren hasta C++ 11, las pequeñas mejoras en C++ 14 no están.
2. Conceptos básicos: Tipos
• Tipos fundamentales
– Enteros
bool: 1 byte, el estandar no especifica tamaño
char, unsigned char, signed char: 1 byte, caracteres ASCII
short, unsigned short: 2 bytes, >= char, <= int
int, unsigned int: 4 bytes, >= short, <= long
__intn: 8, 16, 32, 64, or 128 bits según el valor de n, especifico de MS
long, unsigned long: 4 bytes, >= int
long long: 8 bytes, > long
– Flotantes
float: 4 bytes, más pequeño flotante
double: 8 bytes, >= float
long double: == double
– Unicode:
__wchar_t: nativo o unsigned short
3. Conceptos básicos: Literales
• Cadenas
– char[], wchar[]
– Literales:
char c = “a”;
__wchar_t w = L”a”;
tchar t =_T(“a”);
– Caracteres de escape:
n: nueva línea ?: interrogación
t: tab horizontal ’: comilla simple
v: tab vertical ’’: comilla doble
b: backspace ooo: nmero octal
r: retorno de carro xhhh: número hex
f: pie de formulario 0: null
a: alerta
: barra
5. Conceptos básicos: sentencias
de control
• if ( expression )
statement
[else
statement]
• switch ( expression )
case constant-expression :
statement
[default : statement]
• while ( expression )
statement
• do
statement
while ( expression ) ;
6. Conceptos básicos: sentencias
de control
• for ( init-expression ; cond-expression ; loop-
expression)
statement
• break
• continue
• return
• goto
7. Gestión de memoria: aéreas
• Code Segment: Almacena el código ejecutable del
programa
• Data Segment: Almacena los datos globales.
• Stack Segment: Almacena variables locales,
parámetros y variables temporales.
void f(int i /*stack*/)
{
int j = 0; //stack
void* pint = new BYTE[1]; //heap!!
}
8. Gestión de memoria: new y
delete
• new: asigna memoria
– std::bad_alloc
• delete, delete[]: libera memoria
• new sin delete == fuga de memoria!!!
• Son sobrecargables, casi siempre innecesario
• Llama al destructor
9. Gestión de memoria: smart
pointers
• Evitar la complejidad de usar memoria dinámica (o
contaje de referencias)
• Parece un puntero (patrón proxy, wrapper)
• Estándar: auto_ptr, unique_ptr
• ¿Qué aporta?
– Limpieza e inicialización automáticas
– Exception safety
– Evitar ‘dangling pointers’: NULL cuando se copia
MyClass* p(new MyClass);
MyClass* q = p; delete p;
p->DoSomething(); // Watch out! p is now dangling!
p = NULL; // p is no longer dangling
q->DoSomething(); // Ouch! q is still dangling!
10. Gestión de memoria: smart
pointers
• Limitaciones:
class MyClass { unique_ptr<int> p; // ... };
MyClass x;
MyClass y = x; // x.p now has a NULL pointer
No se puede usar con contenedores de STL porque
manejan los punteros por valor (copia).
Workarround: contenedores de punteros.
Mejor: Otros tipos de smart pointers: refernce counting,
linking, punteros de la librería boost, que veremos
más adelante.
std::auto_ptr ha muerto, deprecated
11. Nuevos smart pointer
• #include <memory>
• std::unique_ptr<>
– Elección por defecto
– Un solo propietario (eleccipor defecto)
• std::shared_ptr<>
– Varios propietarios
– P.e.: Devolver una copia de un puntero y conservarlo
(contenedores).
– Contaje de referencias.
• std::weak_ptr<>
– Evita problemas con referencias cíclicas.
13. OOP: Clases
• Clase: Una clase es un contenedor de uno o más datos
(variables o propiedades miembro) junto a las
operaciones de manipulación de dichos datos
(funciones/métodos miembro).
• Objeto: instanciación de la clase.
• Encapsulación: Solo se manipula el estado de la clase a
través de la interfaz definida por sus métodos miembro.
• Convención: declaración en .h definición en .cpp
class tipo
{
[acceso:] miembros
}
14. OOP: Clases
• Constructores: inicializan el objeto
class T {
public:
T();
T(U u, V v);
}
• Constructor copia
T::T(const T &) {
}
• Operador asignación
T &T::operator=(const T &) {
…
return *this;
}
16. OOP: Clases
• Métodos
– Miembros: public, private, protected
– Friend, solo se usa en sobrecarga de operadores
– Sobrecarga
– Parámetros por defecto
20. OOP: Miscelanea
• Namespaces
• typedef type-declaration synonym;
typedef struct _POINT {
unsigned x;
unsigned y;
} POINT;
permite: POINT p en lugar de struct _POINT p
• RTTI
– Operador typeid
– Clase type_info, no instanciable, no copiable
– /GR (Enable Run-Time Type Information)
21. OOP: Miscelanea
• Cast
– C style: churras en merinas, error en tiempo de
ejecución. No es ‘type safe’.
– const_cast: si es const será por algo
– dynamic_cast
• Solo para tipos polimórficos (al menos un
miembro virtual)
• Hacia abajo por la jerarquía: en tiempo de
ejecución
• Hacia arriba por la jerarquía: en tiempo de
compilación
22. OOP: Miscelanea
• Cast
– static_cast, jerarquías no polimórficas o clases no
relacionadas. No fallará en tiempo de ejecución
nunca.
– reinterpret_cast, si todo lo demás falla. void, no es
type safe precisamente. Síntoma de mal diseño.
– Estrategia: usar static_cast y ver que dice el
compilador.
24. OOP: Exception safety
• Tratamiento de excepciones: try, catch
• Jerarquías de excepciones
• Adquisición segura de recursos
class CResourceManager
{
//Constructor adquiere recurso
//Destructor adquiere recurso
}
25. OOP: Exception safety
• Tres niveles de exception safety
– ‘Basic Guarantee’: Si se lanza una excepción, no se fugará ningún
recurso, y los objetos permanecerá en un estado destructible y
usable, aunque no necesariamente predecible. Es el nivel más
débil de ‘exception safety’, y es apropiado cuando el cliente puede
lidiar con operaciones fallidas que ya han realizado cambios en el
estado del objeto.
– ‘Strong Guarantee’: Si se lanza una excepción, el estado del
programa permanece sin cambio. Este nivel implica semantica de
transaccionalidad, e incluye que las referencias o iteradores dentro
de un contenedor serán invalidadas si una operación falla.
– ‘Nothrow Guarantee’: La función no emitirá una excepción bajo
ninguna circustancia. Ocurre que es imposible implementar las
garantias anteriores si ciertas funciones no garantizan que no
lanzarán excepciones (p.e. destructores). P.e: ninguna operación
de auto_ptr lanza excepción alguna.
26. OOP: Exception safety
• Exception safe copy
– Dos pasos:
• Primero, proporcionar una función Swap() que no lanza
excepciones y que intercambia el estado de los objetos
void T::Swap( T& other ) throw() {
//intercambiar el estado entre *this y other }
• Segundo, implementar el operator=() usando del idioma
“crear un temporal e intercambiar":
T& T::operator=( const T& other ) {
T temp( other ); // realizar la operación
// hacer ‘commit’ sin lanzar excepciones
Swap( temp );
return *this; }
27. OOP: Exception safety
• Herencia y Exception safety
– U implementado en terminos de T si U usa T en su
implementación de cualquier manera
– Si U esta implementado en terminos de T, la seguridad frente a
excepciones de T depende de U
class T : private U { // ... };
T& T::operator=( const T& other ) {
U::operator=( other ); // ???
return *this; }
– Solución: agregación en lugar de herencia.
28. OOP: Exception safety
• Herencia y Exception safety
• Solución: agregación en lugar de herencia.
class T {
// ... private: U* u_; };
T& T::operator=( const T& other ) {
U* temp = new U( *other.u_ ); // realizar la copia lateral
delete u_; // hacer ‘commit’ de la operación
u_ = temp; // usando solo operaciones que no lazan excepciones
return *this; }
29. OOP: Exception safety
• Excepciones en constructores
// Very Buggy Class
class X : Y {
T* t_;
Z* z_;
public:
X()
try
: Y(1)
, t_( new T( static_cast<Y*>(this) )
, z_( new Z( static_cast<Y*>(this), t_ ) )
{
/*...*/
}
catch(...)
// Y::Y or T::T or Z::Z or X::X's body has thrown
{
// Q: should I delete t_ or z_? (note: not legal C++)
}
};
30. OOP: Exception safety
• Excepciones en constructores
– Constructor try-catch, de nula utilidad
– NO usar la lista de inicializadores para adquirir recursos
– Utilizar try catch en el cuerpo del constructor o destructor para
limpiar recursos
– Utilizar RAII - Resource Acquisition Is Initialization
31. OOP: Exception safety
• RAII
class LogFile {
public:
// exception classes
class FileFailedToOpen { };
class WriteFailure { };
LogFile(const char* fileName) : // initialize data member with the file handle
m_file( OpenFile(fileName) ) {
// handle errors automatically
if( m_file == INVALID_HANDLE ) throw FileFailedToOpen(); }
~LogFile() { CloseFile(m_file); }
void write(const char* logLine) {
WriteFile( m_file, logLine ); if(error) throw WriteFailure(); }
private :
FILE_HANDLE m_file;
// avoid copying by declaring a private but unimplemented
// copy-constructor and assignment operator
LogFile (const LogFile&);
LogFile& operator= (const LogFile&);
};
34. Templates
• Una clase no genérica
class String {
//…
public:
String();
String(const char*);
String(const String&);
char GetPos(uint i) const;
}
35. Templates
• Una clase genérica
template<class T> class String {
//…
public:
String();
String(const T*);
String(const String&);
T GetPos(uint i) const
}
• Nos pemite hacer:
String<char> charString;
String<tchar> tcharString;
String<wchar> wcharString
36. Templates
• Una clase generada desde un template es un nuevo tipo.
• Nada lo diferencia de otro tipos no genéricos.
• Aproximación a la implementación: Generalizar una clase
concreta.
• Instanciación de templates: trabajo del compilador
String<char> cs; //El compilador genera el código
37. Templates
• Template parameters
– Pueden ser tipos o parámetros ordinarios
template<class T, int size> class C { };
– Se puede usar un parámetro de tipo en la definición
de otros parámetros
template<class T, T default> class C { };
– Equivalencia de tipos
typedef char CHAR;
String<char> s1;
String<CHAR> s2;
38. Templates
• Type checking
– Errores de sintaxis: en el momento de compilación
del template
– Errores relacionados con los parametros tipo: en el
momento de la instanciación (firs point of
instantation)
template<class T> class Vector{
void Dump {
for (int i = 0; i < _numElem; ++i)
_elem[i].Dump();
}
39. Templates
• Function templates
template<class T> void sort(vector<T>&)
– Los parámetros se deducen de los tipo de los
argumentos
template<class T, int i> T& search(buffer<T,i>, int j)
typedef ByteBuffer buffer<BYTE, 128>;
ByteBuffer b;
shearch(b, 64);
– No siempre es posible
template<class T> T& create();
CPerson c = create<CPerson>();
40. Templates
• Function templates
template<class T> void sort(vector<T>&)
– Los parámetros se deducen de los tipo de los
argumentos
template<class T, int i> T& search(buffer<T,i>, int j)
typedef ByteBuffer buffer<BYTE, 128>;
ByteBuffer b;
shearch(b, 64);
– No siempre es posible
template<class T> T& create();
CPerson c = create<CPerson>();
Habitual para el tipo retornado
41. Templates
• Function templates
template<class T> void sort(vector<T>&)
– Los parámetros se deducen de los tipo de los
argumentos
template<class T, int i> T& search(buffer<T,i>, int j)
typedef ByteBuffer buffer<BYTE, 128>;
ByteBuffer b;
shearch(b, 64);
– No siempre es posible
template<class T> T& create();
CPerson c = create<CPerson>();
42. Templates
• Especialización
– Por defecto, una implementación para todos los
parámetros Tipo
– Nos puede interesar una diferente implementación
para ciertos tipos
– Evita ‘code bloat’, especialmente usando punteros
Vector<int*> vi;
Vector<CPerson*> vp;
Vector <char *>
Solución: especialización para tipos puntero
template<> class Vector<int*> { }; //Total
template<T> class Vector<T*> { }; //Parcial
46. STL
• Librería estándar de C++ basa en Templates.
• Proporciona:
– Clases útiles (string, streams, etc…)
– Contenedores e iteradores
– Algoritmos
47. STL: Contenedores e iteradores
HIGH = first element
current_element = second element
while current_element is within the group of elements
if current_element > HIGH, then HIGH =
current_element
Advance to the next element
end while
• Pseudo-código válido con independencia:
– Del tipo de elementos
– De como se almacenen
48. STL: Contenedores e iteradores
vector<int>::iterator current = values.begin();
int high = *current++;
while (current != values.end())
{
if (*current > high)
{
high = *current;
}
current++;
}
49. STL: Contenedores habituales
• Secuencias
– vector: array, equivalencia vector/array: &foo[0]
– list: lista doblemente linkada.
– queue: FIFO
– deque: estructura similar a un array con eliminación y
adición eficiente de elementos en ambos extremos.
– stack: LIFO (last in, first out) structure.
– priority_queue: cola priorizada.
• Asociativos
– set: conjunto de elementos únicos.
– multiset: conjunto de elementos.
– map: diccionario de valores únicos
– multimap: diccionario de valores.
– Variaciones basadas en hash: búsqueda optimizada en
conjuntos muy grandes.
50. STL: Funciones habituales
• Inserción y extracción de elementos:
– push_front: Inserta un elemento al principio, no
disponible para vectores.
– pop_front: Elimina un elemento al principio, no disponible
para vectores.
– push_back : Inserta un elemento al final.
– pop_back: Eliminar un elemento al final.
• Otros miembros:
– empty: Indica si el contenedor está vacio.
– size: Devuelve el número de elementos.
– insert: Inserta un elemento en una determinada posición.
– erase: Elimina elementos.
– clear: Elimina todos los elementos .
– resize: Cambia el tamaño del contenedor.
– front: Referencia al primer elemento.
– back: Referencia al último elemento.
• Para las secuencias: [] y at, permite acceso directo a un
elemento.
51. STL: Iteradores
• Container<T>::iterator begin();
Container<T >::iterator end();
• Container<T >::const_iterator begin() const;
Container<T >::const_iterator end() const;
• for each (soporte añadido por el compilador, azúcar sintáctico).
53. STL: Algoritmos
• ¡Cientos de algoritmos a nuestra disposición!
• Tipos:
– Búquedas
– Recorridos.
– Ordeando.
– Elimiación de elementos.
• Hacen uso intensivo de iteradores.
• También se pueden usar con arrays y con punteros.
• Principalmente en <algoritm> y <numeric>.
54. STL: Algoritmos habituales
• for_each: Realiza una operación sobre cada elemento.
• find: Busca la primera ocurencia de un valor.
• find_if: Busca el primer elemento que cumple cierta
condición.
• find_first_of: Busca el primer elmento de un contenedor en
otro.
• adjacent_find: Busca la primera ocurrencia de valores
adjacentes iguales.
• count: Cuenta las ocurrencias de un valor.
• count_if: Cuenta las ocurrencias que cumplen una
determinada condición.
• accumulate: Suma los elementos de un contenedor.
• equal: Compara dos rangos.
• max_element: Busca el mayor elemento.
• min_element: Busca el menor elemento.
55. STL: Algoritmos habituales
• transform: Aplica una operación de transformación a los
elementos de un contenedor.
• copy: Copia un contenedor.
• replace: Remplaza los elementos del contenedor.
• replace_if: Remplaza los elementos que cumplen una
condición.
• remove: Elimina elementos.
• remove_if: Elimina elementos que cumplen una condición.
• reverse: Invierte el orden de los elementos.
• random_shuffle: Ordena aleatoriamente los elementos.
• fill: Llena un contenedor con un determinado valor.
• generate: Llena un contenedor con el resultado de una
operación.
56. STL: Algoritmos habituales
• sort: Ordena los elementos.
• stable_sort: Ordena manteniendo el orden de elementos
iguales.
• nth_element: Pone el elemento n en el lugar que le
corresponde.
• binary_search: Busca un valor mediante búsqueda binaria.
58. Expresiones Lambda
1. Clausula de captura
2. Lista de parámetros
3. Especificación de mutabilidad
4. Declaración de excepciones
5. Tipo retornado
6. Cuerpo
61. Async y futures
• std::async(std::launch::async, []{ f(); });
– std::launch::async -> evaluación asíncrona
– std::launch::deferred -> evaluación perezosa
• std::packaged_task -> envuelve cualquier elemento
invocable para poderlo invocar asíncronamente.
• std::future -> acceso al resultado de una operación
asícrona.
62. Thread
• Representan un nuevo hilo de ejecución.
• Se alimentantan de un ‘puntero a función’.
• El namespace thread::this_thread permite domir hilos,
saber el id, hacer yield…
63. Sincronización
• mutex: Acceso exclusivo.
• lock, lock_guard: Bloqueo sobre uno/varios objetos
bloqueables. El hilo solo avanza si puede obtener el lock.
• Condition variables: comunicación entre hilos.
67. Novedades C++ 11
• Expresiones constantes
constexpr int dame_cinco() {return 5;} int algun_valor[dame_cinco() + 7];
constexpr double aceleracion_de_gravedad = 9.8; constexpr double
gravedad_lunar = aceleracion_de_gravedad / 6.0;
• Incialización rapida y de listas
struct Objeto { float primero; int segundo; };
Objeto escalar = {0.43f, 10}; // Un objeto, con primero=0.43f y segundo=10
Objeto matriz[] = {{13.4f, 3}, {43.28f, 29}, {5.934f, 17}}; // Una matriz con
tres objetos
std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" };
68. Novedades C++ 11
• Inferencia de tipos
auto algun_extraño_tipo_llamable = boost::bind(&alguna_funcion, _2, _1,
algun_objeto);
auto otra_variable = 5;
int un_entero;
decltype(un_entero) otro_entero = 5; //En tiempo de compilación
69. Novedades C++ 11
• Llamadas entre constructores
class AlgunTipo {
int _num;
public:
AlgunTipo(int num) : numero(num) {}
AlgunTipo() : AlgunTipo(42) {}
};
70. Novedades C++ 11
• Herencia de constructores
class ClaseBase {
public: ClaseBase(int valor);
};
class ClaseDerivada : public ClaseBase {
public:
using ClaseBase::ClaseBase;
};
71. Novedades C++ 11
• Override
struct Base { virtual void f(float); };
struct Derivada : Base { virtual void f(int) override; //Error };
• Final -> sellado de herencia
struct Base1 final { };
struct Derivada1 : Base1 { }; //Error
struct Base2 { virtual void f() final; };
struct Derivada2 : Base2 { void f(); //Error };
72. Noveades C++ 11
• Constante de puntero nulo
char *pc = nullptr; // OK
int *pi = nullptr; // OK
bool b = nullptr; // OK. b es false.
int i = nullptr; // error
foo(nullptr); // invoca foo(char *), no foo(int);
73. Novedades C++ 11
• Nuevos tipos de literales
– L"I'm a wchar_t string."
– u8"I'm a UTF-8 string."
– u“I'm a UTF-16 string."
– U"I'm a UTF-32 string.“
• Evitar caracteres de escape
– R"(The String Data Stuff " )"
– R"delimiter(The String Data Stuff " )delimiter"
wchar_t