domingo 12 de julio de 2009

STL vector en vez de los clásicos buffers de C

Algunas veces tenemos que crear buffers temporales. Por ejemplo, la función sprintf necesita de un buffer para poder dejar la cadena resultante. Ejemplo:
char buf[256];
sprintf(buf, "%d", 12345);
// usar "buf"...

Si queremos mantener el buffer en heap:
char* buf = malloc(256);
sprintf(buf, "%d", 12345);
// usar "buf"...
free(buf);

En C++ podríamos hacer uso de los operadores new[]/delete[]:
char* buf = new char[256];
sprintf(buf, "%d", 12345);
// usar "buf"...
delete[] buf;

Pero es aconsejable evitar la creación de arreglos con new[], y en su lugar hacer uso de std::vector:
std::vector<char> buf(256);
sprintf(&buf[0], "%d", 12345);
// usar "&buf[0]" en vez de "buf"...

El resultado: tenemos un buffer en el heap que se libera automáticamente (~std::vector) al salir del ámbito de la función que lo utiliza.

4 comments:

Hernán Eche dijo...

Está bueno tu blog, me gusta la manera didáctica, (lo intento también), aunque cuesta, vale! (Explicar no es escupir información)

En cuanto al post..
opino de STL: cuando supe de esta librería, me gustó su funcionalidad, pero...

comparo estas lineas

char buf[256];

std::vector< char > buf(256);

La primera no es dinámica pero es Bella.

Pienso, debería esto estar integrado en el lenguaje?
(cosa que me pregunto casi con todas las librerías)jaja

¿Será que la flexibilidad, la posibilidad de más opciones complica y atenta contra la belleza?

dacap dijo...

Hola Hernán, gracias por el comentario!

Yo opino que está bueno que la STL esté integrada al lenguaje mismo. Te permite hacer cosas en C++ sin necesidad de empezar desde cero y tener que resolver problemas básicos (como "¿tengo listas enlazadas? uh no, las tengo q copiar desde este otro proyecto"...)

Además, si no las usas no se te meten en el binario (todo el código son templates y en .h). Y es genérica, se compila lo mínimo necesario para tus únicos requerimientos (tipos de datos, funciones y métodos utilizados, optimizada para tu CPU, etc.).

Ahora volvamos al tema de la comparación :) ... Si comparamos bellezas, tenemos que comparar los mismos géneros (nade de ir comparando minas con yeguas). Si usas memoria dinámica, en C es un asco:

char* buf = malloc(256);
free(buf);

Y no hay forma de mejorar eso (podés ponerle mejores nombres a las funciones, pero siempre vas a terminar llamando vos mismo a la liberación).

En C++, podes llevar todo a un nivel de belleza de alta costura:

typedef std::vector<char> Buffer;
...
Buffer buf(256);

No hace falta decir que la última línea es bella, dinámica y usa la STL :)

Aitor dijo...

Hola, me gustaria que me dijeras como puedo crear un vector STL dentro de un objeto. Me explico, estoy haciendo un juego de cuatro en raya y quiero crear una variable tal que "vector < vector < int > > tablero (12, 10);" dentro de una clase juego, como se hace??

Gracias y un saludo!!

David Capello dijo...

Hola Aitor, deberías hacer lo siguiente:
1) definir una clase "juego" con un constructor
2) colocarle un miembro (preferentemente privado) que se llame "tablero" y sea de tipo vector<vector<int> >
3) en el constructor de la clase (juego::juego) deberías inicializar la variable miembro tablero de tal forma que te quede la matriz que vos deseas.

Un ejemplo para un tablero de 3x3:

vector<vector<int> > tablero;
tablero.resize(3);
for (size_t i=0; i<3; ++i)
  tablero[i].resize(3);

Y para recorrer el tablero:
for (size_t i=0; i<tablero.size(); ++i)
  for (size_t j=0; j<tablero[i].size(); ++j)
    printf("%dx%d = %d\n", i, j, tablero[i][j]);

Espero que te sirva para resolver tu problema. Saludos!