<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4295741868585735005</id><updated>2011-12-31T01:06:36.512-03:00</updated><category term='ensamblador'/><category term='operadores'/><category term='conceptos'/><category term='list'/><category term='tiempo'/><category term='auto_ptr'/><category term='optimización'/><category term='interfaces'/><category term='version'/><category term='clases'/><category term='memory leaks'/><category term='c'/><category term='string'/><category term='queue'/><category term='algoritmo'/><category term='abstracción'/><category term='raii'/><category term='buffer'/><category term='mingw'/><category term='compilar'/><category term='scoped pointer'/><category term='shared pointers'/><category term='c++0x'/><category term='gcc'/><category term='exception'/><category term='instalación'/><category term='iostream'/><category term='parser'/><category term='leaks'/><category term='vector'/><category term='c++'/><category term='stl'/><category term='c++11'/><title type='text'>C más o menos − Programación en C++</title><subtitle type='html'>Programación en C++</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-1058770412296926801</id><published>2011-12-23T16:12:00.000-03:00</published><updated>2011-12-23T16:12:48.092-03:00</updated><title type='text'>Año nuevo</title><content type='html'>Bueno, este año fue poco productivo en este blog. El próximo no prometo mucho más, pero espero mejorar. Dejo un par de links que agregué en la sidebar:&lt;ul&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/apps/mediawiki/predef/index.php?title=Main_Page"&gt;Pre-defined C/C++ Compiler Macros&lt;/a&gt;: Si alguna vez tenemos que detectar la versión de un compilador o en qué plataformas estamos, estas macros pueden ayudarnos a escribir código portable.&lt;li&gt;&lt;a href="http://en.cppreference.com/w/cpp"&gt;C++ Reference Wiki&lt;/a&gt;: Una wiki con referencia sobre C++ y C++11&lt;/ul&gt;Los próximos años pueden llegar a ser los mejores años de C++. Con &lt;a href="http://clang.llvm.org/"&gt;clang&lt;/a&gt; avanzando sobre &lt;a href="http://gcc.gnu.org/"&gt;gcc&lt;/a&gt;, es probable que aparezcan herramientas muy importantes para ayudar a programar en C++. Aquí les dejo un video:&lt;p&gt;&lt;iframe width="560" height="315" src="http://www.youtube.com/embed/mVbDzTM21BQ" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;p&gt;¡Feliz año nuevo!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-1058770412296926801?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/1058770412296926801/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=1058770412296926801' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/1058770412296926801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/1058770412296926801'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2011/12/ano-nuevo.html' title='Año nuevo'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/mVbDzTM21BQ/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-6510917909811836739</id><published>2011-09-21T01:03:00.001-03:00</published><updated>2011-09-21T01:03:43.717-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='c++11'/><title type='text'>Código C++ moderno</title><content type='html'>Una excelente charla de Herb Sutter&amp;nbsp;(en inglés)&amp;nbsp;introduciendo algunas de las novedades del nuevo&amp;nbsp;estándar&amp;nbsp;C++11 y sobre cómo escribir código en C++ aprovechando todo el conocimiento acumulado en estos años (si nunca leíste &lt;a href="http://www.gotw.ca/publications/c++cs.htm"&gt;C++ Coding Standards&lt;/a&gt; de Herb Sutter y Andrei Alexandrescu, compralo):&lt;br /&gt;&lt;blockquote&gt;&lt;a href="http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-835T"&gt;http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-835T&lt;/a&gt;&lt;/blockquote&gt;Los puntos tratados que no podes dejar pasar por alto:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El nuevo significado de la palabra &lt;a href="http://en.wikipedia.org/wiki/C%2B%2B11#Type_inference"&gt;auto&lt;/a&gt;&amp;nbsp;para inferir tipos automáticamente.&lt;/li&gt;&lt;li&gt;La nueva sintaxis de&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/C%2B%2B11#Lambda_functions_and_expressions"&gt;lambdas&lt;/a&gt;&amp;nbsp;para definir functors en línea y usarlos en algoritmos estándares (ej: for_each()).&lt;/li&gt;&lt;li&gt;&lt;i&gt;Exception safety&lt;/i&gt; y &lt;i&gt;heap lifetime&lt;/i&gt; con&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/C%2B%2B11#General-purpose_smart_pointers"&gt;smart pointers&lt;/a&gt;, los cuales ya tenemos varios posts en este mismo blog sobre el concepto de smart pointers y &lt;a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization"&gt;RAII&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Nuevos contenedores de tipo &lt;a href="http://en.wikipedia.org/wiki/C%2B%2B11#Hash_tables"&gt;hash table&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors"&gt;Move semantics&lt;/a&gt;&amp;nbsp;que evita la creación y destrucción de objetos temporales innecesarias (ej: al retornar por valor).&lt;/li&gt;&lt;li&gt;Varios pequeños nuevos coding standards de C++11: funciones begin()/end(), &lt;i&gt;override&lt;/i&gt; explícito, idioma pimpl con unique_ptr&amp;lt;&amp;gt;, etc.&lt;/li&gt;&lt;/ul&gt;En futuros posts voy a dedicar algo de tiempo en introducir estos temas y explicar por qué nacieron cada una de estas modificaciones en el nuevo estándar de C++.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-6510917909811836739?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/6510917909811836739/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=6510917909811836739' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6510917909811836739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6510917909811836739'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2011/09/codigo-c-moderno.html' title='Código C++ moderno'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-7673805625616016325</id><published>2011-03-08T13:09:00.001-03:00</published><updated>2011-03-08T13:12:35.022-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='queue'/><category scheme='http://www.blogger.com/atom/ns#' term='list'/><category scheme='http://www.blogger.com/atom/ns#' term='stl'/><title type='text'>Cola de prioridades (STL priority_queue)</title><content type='html'>La cola de prioridades es una estructura de datos que se puede visualizar como una bolsa, donde podemos ir metiendo elementos uno atrás del otro, pero sólo los podemos retirar según un criterio de prioridad. Por ejemplo, en el caso de un ladrón obsesivo-compulsivo, podría robar un banco cargando bolsas de dinero sin ningún criterio, y al vaciarla podría retirar los billetes según su valor (primero los de $100, luego los de $50, etc.).&lt;br /&gt;&lt;br /&gt;Otro ejemplo, imaginemos que tenemos un barco:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;queue&amp;gt;&lt;br /&gt;#include &amp;lt;list&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class Barco {&lt;br /&gt;public:&lt;br /&gt;  void subirPasajero(const Pasajero&amp; pasajero);&lt;br /&gt;  void abandonarBarco(list&amp;lt;Pasajero&amp;gt;&amp;amp; pasajerosEnOrden);&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  priority_queue&amp;lt;Pasajero&amp;gt; pasajeros_;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La función subirPasajero() debe agregar un pasajero al barco, y abandonarBarco() debe sacar todos los pasajeros del barco y colocarlos (por orden de prioridad) en la lista que se recibe como argumento:&lt;br /&gt;&lt;pre class="prettyprint"&gt;void Barco::subirPasajero(const Pasajero&amp;amp; pasajero)&lt;br /&gt;{&lt;br /&gt;  pasajeros_.push(pasajero);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void Barco::abandonarBarco(list&amp;lt;Pasajero&amp;gt;&amp;amp; pasajerosEnOrden)&lt;br /&gt;{&lt;br /&gt;  while (!pasajeros_.empty()) {&lt;br /&gt;    pasajerosEnOrden.push_back(pasajeros_.top());&lt;br /&gt;    pasajeros_.pop();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Tenga en cuenta que la función miembro pop() de las colas en C++ (queue, priority_queue, etc.) no retornan el valor extraído. Esto es así para evitar crear copias de los objetos dentro de la cola. De este modo la función top() devuelve una referencia al elemento mismo que se encuentra en la cola, y pop() lo remueve sin devolver nada. Así nos evitamos de crear copias temporales de la instancia removida.&lt;br /&gt;&lt;br /&gt;Para poder usar la priority_queue sobre un tipo de dato propio (como Pasajero), debemos ofrecer una implementación del operator&amp;lt;() para comparar distintas instancias de nuestro tipo de dato (este operador se utiliza para saber qué elemento debe salir último de la cola, es decir, el menor elemento tiene menor prioridad):&lt;br /&gt;&lt;pre class="prettyprint"&gt;enum Prioridad { Capitan, Hombre, Mujer, Ninio };&lt;br /&gt;&lt;br /&gt;class Pasajero {&lt;br /&gt;public:&lt;br /&gt;  Pasajero(Prioridad p) : prioridad_(p) { }&lt;br /&gt;&lt;br /&gt;  bool operator&amp;lt;(const Pasajero&amp;amp; otro) const {&lt;br /&gt;    return prioridad_ &amp;lt; otro.prioridad_;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  Prioridad prioridad() const { return prioridad_; }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  Prioridad prioridad_;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;De este modo, el capitán tiene prioridad 0 y es tomado en cuenta como el de menor prioridad para abandonar el barco. Los pasajeros que mayor prioridad tienen de abandonar el barco son las mujeres y los niños. En este caso podrían tener igual prioridad, no tendría mucho sentido salvar a todos los niños sin sus respectivas madres.&lt;br /&gt;&lt;br /&gt;Ahora podemos crear un ejemplo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  Barco titanic;&lt;br /&gt;  titanic.subirPasajero(Pasajero(Capitan));&lt;br /&gt;  titanic.subirPasajero(Pasajero(Mujer));&lt;br /&gt;  titanic.subirPasajero(Pasajero(Hombre));&lt;br /&gt;  titanic.subirPasajero(Pasajero(Mujer));&lt;br /&gt;  titanic.subirPasajero(Pasajero(Ninio));&lt;br /&gt;  titanic.subirPasajero(Pasajero(Hombre));&lt;br /&gt;  titanic.subirPasajero(Pasajero(Ninio));&lt;br /&gt;  // ...&lt;br /&gt;&lt;br /&gt;  list&amp;lt;Pasajero&amp;gt; pasajeros;&lt;br /&gt;  titanic.abandonarBarco(pasajeros);&lt;br /&gt;  &lt;br /&gt;  for (list&amp;lt;Pasajero&amp;gt;::iterator it = pasajeros.begin(),&lt;br /&gt;         end = pasajeros.end(); it != end; ++it) {&lt;br /&gt;    cout &amp;lt;&amp;lt; it-&amp;gt;prioridad() &amp;lt;&amp;lt; "\n";&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;El anterior ejemplo imprime:&lt;br /&gt;&lt;pre class="console"&gt;3&lt;br /&gt;3&lt;br /&gt;2&lt;br /&gt;2&lt;br /&gt;1&lt;br /&gt;1&lt;br /&gt;0&lt;br /&gt;&lt;/pre&gt;Lo que significa que, sin importar el orden en el cual agregamos los pasajeros, primero extraemos los niños, luego las mujeres, los hombres, y finalmente el capitán.&lt;br /&gt;&lt;br /&gt;Más información:&lt;br /&gt;&lt;a href="http://www.cplusplus.com/reference/stl/priority_queue/"&gt;http://www.cplusplus.com/reference/stl/priority_queue/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Priority_queue"&gt;http://en.wikipedia.org/wiki/Priority_queue&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-7673805625616016325?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/7673805625616016325/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=7673805625616016325' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/7673805625616016325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/7673805625616016325'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2011/03/cola-de-prioridades-stl-priorityqueue.html' title='Cola de prioridades (STL priority_queue)'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-8958120184413860352</id><published>2010-09-18T16:32:00.000-03:00</published><updated>2010-09-18T16:32:29.021-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='iostream'/><title type='text'>Iostream - Redireccionar clog para "loguear" en un archivo</title><content type='html'>La &lt;a href="http://www.cplusplus.com/reference/iostream/"&gt;iostream&lt;/a&gt; es la librería de entrada y salida de C++. Existen algunos &lt;a href="http://en.wikipedia.org/wiki/Standard_streams"&gt;streams estándares&lt;/a&gt; de salida: std::cout, std::cerr y std::clog. El primero apunta a la consola, y los dos últimos... también. Las diferencias son estas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;cout apunta a la salida estándar STDOUT (texto de resultado esperado de un programa);&lt;br /&gt;&lt;li&gt;cerr y clog apuntan a STDERR (salida de errores y cualquier otra porquería).&lt;br /&gt;&lt;/ul&gt;Aunque a primera vista todo el texto se envía a la consola, uno puede redireccionar la salida a otros lados. Por ejemplo, imaginemos que tenemos el siguiente programa test.exe:&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  cout &amp;lt;&amp;lt; "A\n";&lt;br /&gt;  cerr &amp;lt;&amp;lt; "B\n";&lt;br /&gt;  clog &amp;lt;&amp;lt; "C\n";&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;Al ejecutarlo, obtenemos por pantalla las tres líneas:&lt;pre class="console"&gt;test.exe [ENTER]&lt;br /&gt;A&lt;br /&gt;B&lt;br /&gt;C&lt;br /&gt;&lt;/pre&gt;Pero resulta interesante saber que podemos redireccionar el STDOUT a un archivo y el STDERR a otro. Ejemplo:&lt;pre class="console"&gt;test.exe 1&gt;stdout.txt 2&gt;stderr.txt&lt;/pre&gt;¿Qué demonios es 1 y 2? Los archivos tienen un &lt;a href="http://en.wikipedia.org/wiki/File_descriptor"&gt;descriptor que los identifica&lt;/a&gt;, 1 es para la STDOUT, y 2 para STDERR. El signo mayor (&amp;gt;) significa que "quiero redireccionar toda la salida de texto que vaya para este descriptor a este archivo". En el anterior ejemplo logramos obtener dos archivos distintos, stdout.txt que contiene una línea (A), y stderr.txt que contiene dos líneas (B y C).&lt;p&gt;Generalmente, los &lt;a href="http://en.wikipedia.org/wiki/Server_log"&gt;logs&lt;/a&gt; van a un archivo, no a la pantalla. Aunque por defecto clog mande todo a STDERR, resulta útil redireccionar este stream a un archivo propio (por ejemplo, test.log). De esta forma, podemos hacer uso de clog para "loguear" todo lo que nuestro programa hace.&lt;p&gt;&lt;b&gt;¿Cómo se redirecciona clog?&lt;/b&gt; Básicamente los streams de C++ tienen un &lt;a href="http://www.cplusplus.com/reference/iostream/streambuf/"&gt;streambuf&lt;/a&gt; asociado, y éste es el realmente encargado de leer y escribir datos (en la pantalla, en un archivo, en un string en memoria, etc.). Por lo tanto, si creamos un fstream y le colocamos su propio streambuf a clog, podemos usar clog como un "alias" del fstream original (clog va a estar compartiendo el mismo streambuf que el fstream). El código resultante es bastante sencillo:&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;fstream&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  // Creamos un archivo de salida para logging.&lt;br /&gt;  ofstream test_log;&lt;br /&gt;  test_log.open("test.log");&lt;br /&gt;&lt;br /&gt;  // Obtenemos el streambuf actual de clog (esto&lt;br /&gt;  // lo usaremos luego para restaurar el streambuf&lt;br /&gt;  // a su valor original, por si las moscas).&lt;br /&gt;  streambuf* old_rdbuf = clog.rdbuf();&lt;br /&gt;&lt;br /&gt;  // Reemplazamos el streambuf de clog con el del archivo.&lt;br /&gt;  // Ahora ambos streams utilizarán el mismo streambuf (es&lt;br /&gt;  // decir, escriben en el archivo test.log).&lt;br /&gt;  clog.rdbuf(test_log.rdbuf());&lt;br /&gt;&lt;br /&gt;  // Hacemos lo mismo que el ejemplo original.&lt;br /&gt;  cout &amp;lt;&amp;lt; "A\n";&lt;br /&gt;  cerr &amp;lt;&amp;lt; "B\n";&lt;br /&gt;  clog &amp;lt;&amp;lt; "C\n";&lt;br /&gt;  &lt;br /&gt;  // Restauramos el viejo streambuf de clog.&lt;br /&gt;  clog.rdbuf(old_rdbuf);&lt;br /&gt;&lt;br /&gt;  // Cerramos el archivo.&lt;br /&gt;  test_log.close();&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;Y listo, ahora podemos hacer lo mismo que antes:&lt;pre class="console"&gt;test.exe 1&gt;stdout.txt 2&gt;stderr.txt&lt;/pre&gt;Con lo cual obtenemos tres archivos:&lt;ul&gt;&lt;li&gt;stdout.txt con la línea A.&lt;br /&gt;&lt;li&gt;stderr.txt con la línea B.&lt;br /&gt;&lt;li&gt;test.log con la línea C.&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-8958120184413860352?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/8958120184413860352/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=8958120184413860352' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/8958120184413860352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/8958120184413860352'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2010/09/iostream-redireccionar-clog-para.html' title='Iostream - Redireccionar clog para &quot;loguear&quot; en un archivo'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-2808595550976028197</id><published>2010-08-30T20:45:00.003-03:00</published><updated>2010-09-13T12:31:04.103-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>Miembros virtuales</title><content type='html'>Una &lt;a href="http://en.wikipedia.org/wiki/Virtual_function"&gt;función miembro virtual&lt;/a&gt; tiene la característica de poder ser sobrecargada por subclases para agregar un comportamiento propio. Pero existen dos lugares en donde las funciones virtuales toman un comportamiento especial: en los constructores y los destructores.&lt;br /&gt;&lt;br /&gt;Veamos el siguiente ejemplo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class Lugar {&lt;br /&gt;public:&lt;br /&gt;  Lugar() {                     // El lugar es creado&lt;br /&gt;    creacion();                 // Llamamos a la función virtual&lt;br /&gt;  }&lt;br /&gt;  virtual ~Lugar() {            // El lugar es destruido&lt;br /&gt;    destruccion();              // Llamamos a la función virtual&lt;br /&gt;  }&lt;br /&gt;protected:&lt;br /&gt;  virtual void creacion()    { }&lt;br /&gt;  virtual void destruccion() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class Universo : public Lugar {&lt;br /&gt;protected:&lt;br /&gt;  void creacion()    { cout &amp;lt;&amp;lt; "Big Bang\n"; }&lt;br /&gt;  void destruccion() { cout &amp;lt;&amp;lt; "Big Crunch\n"; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  Universo i_am_god;  // ¿Qué imprime este programa?&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;La idea de todo método virtual es poder proporcionar puntos de extensión a las clases derivadas. En este caso, ¿&lt;i&gt;Lugar::creacion&lt;/i&gt; funciona como punto de extensión para clases derivadas? La respuesta es: no. El anterior programa no imprime nada.&lt;/p&gt;&lt;p&gt;Aunque creamos una instancia de &lt;i&gt;Universo&lt;/i&gt;, ni el método &lt;i&gt;Universo::creacion&lt;/i&gt; ni &lt;i&gt;Universo::destruccion&lt;/i&gt; se llamaron. ¿A qué se debe esto? Imaginemos que al crear un &lt;i&gt;Universo&lt;/i&gt;, primero debemos crear un &lt;i&gt;Lugar&lt;/i&gt; en su totalidad, para luego comenzar a crear el universo. Es por eso que si llamamos a &lt;i&gt;creacion&lt;/i&gt; mientras estamos construyendo el &lt;i&gt;Lugar&lt;/i&gt;, no podemos alcanzar el método &lt;i&gt;Universo::creacion&lt;/i&gt; ya que el &lt;i&gt;Universo&lt;/i&gt; todavía no comenzó a ser construido (no tiene un &lt;i&gt;Lugar&lt;/i&gt; completamente construido donde existir).&lt;/p&gt;&lt;p&gt;La secuencia correcta es:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Alojamos un cacho de memoria suficiente como para que entre el universo.&lt;br /&gt;Algo así como hacer un: &lt;i&gt;this = malloc(sizeof(Universo))&lt;/i&gt; en C.&lt;br /&gt;&lt;li&gt;Construimos el &lt;i&gt;Lugar&lt;/i&gt; usando la memoria recién obtenida como puntero &lt;i&gt;this&lt;/i&gt;.&lt;br /&gt;&lt;li&gt;Luego construimos el &lt;i&gt;Universo&lt;/i&gt;.&lt;br /&gt;&lt;li&gt;Y recién ahí somos capaces de llamar a &lt;i&gt;Universo::creacion&lt;/i&gt; y asegurarnos que estaremos usando el método especializado de la subclase.&lt;br /&gt;&lt;/ol&gt;&lt;p&gt;&lt;b&gt;¿Puedo llamar a &lt;i&gt;creacion&lt;/i&gt; dentro del constructor de &lt;i&gt;Universo&lt;/i&gt;?&lt;/b&gt; La respuesta es sí, todo es posible. ¿Es correcto? Mmmhh, depende, si alguien hace una subclase de &lt;i&gt;Universo&lt;/i&gt; y sobreescribe &lt;i&gt;creacion&lt;/i&gt;, nuevamente estará en el mismo problema que estamos mostrando aquí.&lt;/p&gt;&lt;p&gt;&lt;b&gt;¿Por qué en el destructor de &lt;i&gt;Lugar&lt;/i&gt; no llama a &lt;i&gt;Universo::destruccion&lt;/i&gt;?&lt;/b&gt; Porque el &lt;i&gt;Universo&lt;/i&gt; ya está destruido (¿cruncheado?) para cuando llegamos al destructor del &lt;i&gt;Lugar&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;&lt;b&gt;¿Cómo lo soluciono?&lt;/b&gt; Usar puntos de extensión en los constructores y destructores presentan más problemas que ventajas. La solución es no usarlos. Solución (obvia):&lt;/p&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class Lugar {&lt;br /&gt;public:&lt;br /&gt;  Lugar() { }&lt;br /&gt;  virtual ~Lugar() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class Universo : public Lugar {&lt;br /&gt;public:&lt;br /&gt;  Universo()  { cout &amp;lt;&amp;lt; "Big Bang\n"; }&lt;br /&gt;  ~Universo() { cout &amp;lt;&amp;lt; "Big Crunch\n"; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  Universo i_am_god;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;En un próximo post voy a dar un ejemplo más complejo donde esto no sirve.&lt;/p&gt;&lt;p&gt;&lt;b&gt;¿Y qué sucede si llamo una función miembro abstracta en el constructor o destructor?&lt;/b&gt; Es el desastre total. Completamente ilegal. Imposible. Una violación absoluta a la razón y el sentido común. Imagine este código:&lt;/p&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class Lugar {&lt;br /&gt;public:&lt;br /&gt;  Lugar() { creacion(); }        // Ja llamo a creacion()&lt;br /&gt;protected:&lt;br /&gt;  virtual void creacion() = 0;   // Jaja y no lo defino ;)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class Universo : public Lugar {&lt;br /&gt;protected:&lt;br /&gt;  void creacion() { }            // Jajaja sólo puede llamarme a mí!&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  Universo i_am_god_x2;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Al compilar este código con gcc obtenemos un warning porque estamos llamando un método abstractor en el constructor, y un error de enlace al crear el ejecutable ya que &lt;i&gt;Lugar::creacion&lt;/i&gt; no está definido:&lt;/p&gt;&lt;pre class="console"&gt;test.cpp: In constructor 'Lugar::Lugar()':&lt;br /&gt;test.cpp:7:22: warning: abstract virtual 'virtual void Lugar::creacion()' called from constructor&lt;br /&gt;C:\temp\ccstr9Hr.o:test.cpp:(.text$_ZN5LugarC2Ev[Lugar::Lugar()]+0x16): undefined reference to `Lugar::creacion()'&lt;br /&gt;collect2: ld returned 1 exit status&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Aunque dijimos explícitamente que Lugar::creacion() es abstracto (=0), eso no significa que no debamos definirlo en este caso tan particular.&lt;/p&gt;&lt;p&gt;Referencias:&lt;br&gt;Sutter, Herb &amp; Alexandrescu, Andrei (2004). Item 49: Avoid calling virtual functions in constructors and destructors. &lt;em&gt;C++ Coding Standards: 101 Rules, Guidelines, and Best Practices.&lt;/em&gt; Boston, MA: Addison-Wesley Professional, (ISBN 0321113586).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-2808595550976028197?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/2808595550976028197/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=2808595550976028197' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/2808595550976028197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/2808595550976028197'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2010/08/miembros-virtuales.html' title='Miembros virtuales'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-5358250520945482732</id><published>2010-06-06T14:35:00.010-03:00</published><updated>2010-06-06T15:00:26.899-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='instalación'/><category scheme='http://www.blogger.com/atom/ns#' term='compilar'/><title type='text'>Descargar MinGW con gcc 4.5 automáticamente</title><content type='html'>Este post se podría llamar:&lt;br /&gt;&lt;blockquote&gt;¿Cómo instalar MinGW?&lt;br /&gt;¿Cómo instalar y usar gcc 4.5 en Windows?&lt;br /&gt;¿Cómo compilar programas de C o C++ en Windows?&lt;br /&gt;O también, ¿puedo portar MinGW en un pendrive?&lt;br /&gt;&lt;/blockquote&gt;Cualquiera de los casos se responde con el siguiente archivo: &lt;a href="http://github.com/downloads/dacap/mingw-downloader/MinGW-Downloader-0.2.zip"&gt;MinGW-Downloader-0.2.zip&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Los pasos a seguir son los siguientes:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Cree una carpeta donde descomprimir MinGW-Downloader-0.2.zip (por ejemplo, C:\Compilers, o C:\GNU, lo importante es que la carpeta no tenga espacios!)&lt;br /&gt;&lt;li&gt;Descomprima MinGW-Downloader-0.2.zip en esa carpeta&lt;br /&gt;&lt;li&gt;Ejecute el archivo "C:\Compilers\MinGW-Downloader\MinGW-4.5-Downloader.bat"&lt;br /&gt;&lt;li&gt;Espere...&lt;br /&gt;&lt;li&gt;Una vez finalizado deberá ver algunos mensajes en la pantalla diciéndole si tuvo éxito (SUCCESS), inclusive el script intenta compilar un programa en C y otro en C++.&lt;br /&gt;&lt;li&gt;Listo, ya tiene MinGW con gcc 4.5 disponible en su máquina.&lt;br /&gt;&lt;/ol&gt;Puede usar el script "Run-cmd-with-MinGW-4.5.bat" para ejecutar la línea de comandos de Windows y tener el compilador disponible (gcc, g++, etc.) en la variable PATH. Lo importante es que el proceso de descarga no modifica ninguna variable de entorno suya (PATH), por lo tanto, podría borrar la carpeta "C:\Compilers" y empezar desde cero siempre que así lo desee.&lt;br /&gt;&lt;br /&gt;Puede mover la carpeta "C:\Compilers\MinGW-Downloader\MinGW-4.5" a "C:\MinGW-4.5" y borrar "C:\Compilers\MinGW-Downloader" completamente. Si quiere tener el compilador disponible desde cualquier aplicación (por ejemplo, desde un editor de texto o IDE), podría agregar la ruta "C:\MinGW-4.5\bin" a su PATH.&lt;br /&gt;&lt;br /&gt;Cabe destacar que la carpeta "MinGW-4.5" ("C:\Compilers\MinGW-Downloader\MinGW-4.5") y el archivo "Run-cmd-with-MinGW-4.5.bat" los puede mover donde usted desee (por ejemplo, llevarlos en un pen drive), sólo tenga en cuenta que para hacer esto los dos tienen que estar en el mismo directorio (e.j. "C:\MinGW-4.5" y "C:\Run-cmd-with-MinGW-4.5.bat").&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-5358250520945482732?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/5358250520945482732/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=5358250520945482732' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/5358250520945482732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/5358250520945482732'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2010/06/descargar-mingw-con-gcc-45.html' title='Descargar MinGW con gcc 4.5 automáticamente'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-4303488601552155816</id><published>2010-05-29T15:59:00.003-03:00</published><updated>2010-06-01T12:00:42.598-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scoped pointer'/><category scheme='http://www.blogger.com/atom/ns#' term='c++0x'/><category scheme='http://www.blogger.com/atom/ns#' term='shared pointers'/><category scheme='http://www.blogger.com/atom/ns#' term='memory leaks'/><title type='text'>Shared Pointers de C++0x</title><content type='html'>En C usted puede hacer esto:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;&lt;br /&gt;struct Persona { };&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  Persona* a = malloc(sizeof(Persona));&lt;br /&gt;  free(a);&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Un ejemplo equivalente en C++:&lt;br /&gt;&lt;pre class="prettyprint"&gt;class Persona { };&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  Persona* a = new Persona();&lt;br /&gt;  delete a;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Por cada &lt;b&gt;malloc&lt;/b&gt; existe un &lt;b&gt;free&lt;/b&gt; (al menos que use reallocs), y por cada &lt;b&gt;new&lt;/b&gt; existe un &lt;b&gt;delete&lt;/b&gt; (y por cada new[] un delete[]).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;¿Existe una forma por la cual C++ se "entere" que ya no quiero usar un puntero?&lt;/b&gt; La respuesta es: No, no existe. C++ no tiene un &lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"&gt;garbage collector&lt;/a&gt;. Pero existen &lt;a href="http://cmasomenos.blogspot.com/2009/11/punteros-por-ambito-scoped-pointers.html"&gt;clases que pueden ayudarnos&lt;/a&gt;, como el viejo y tan poco querido &lt;a href="http://cmasomenos.blogspot.com/2008/06/excepciones-raii-y-autoptr.html"&gt;auto_ptr&lt;/a&gt;, o los mejorados &lt;a href="http://www.google.com/search?q=unique_ptr+Class&amp;btnI=1"&gt;unique_ptr&lt;/a&gt;, &lt;a href="http://www.google.com/search?q=shared_ptr+Class&amp;btnI=1"&gt;shared_ptr&lt;/a&gt; y &lt;a href="http://www.google.com/search?q=weak_ptr+Class&amp;btnI=1"&gt;weak_ptr&lt;/a&gt; del nuevo estándar de C++0x (o el &lt;a href="http://en.wikipedia.org/wiki/C%2B%2B_Technical_Report_1#Smart_pointers"&gt;TR1&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Un &lt;em&gt;shared pointer&lt;/em&gt; es una clase que se encarga de guardar un puntero a un objeto (o tipo de dato), y cuenta la cantidad de referencias que se están haciendo a dicho objeto (es decir, la cantidad de shared pointers que apuntan al mismo objeto). El último shared pointer que se destruya (cuando las referencias llegan a cero), será el encargado de borrar el objeto apuntado (mediante un simple delete).&lt;br /&gt;&lt;br /&gt;Un ejemplo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;  // Aquí debería estar shared_ptr&amp;lt;&amp;gt; (GCC 4.4)&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class Persona {&lt;br /&gt;  int n;&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;  Persona(int n) : n(n) {&lt;br /&gt;    cout &amp;lt;&amp;lt; "Nace la persona " &amp;lt;&amp;lt; n &amp;lt;&amp;lt; "\n";&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  ~Persona() { &lt;br /&gt;    cout &amp;lt;&amp;lt; "Muere la persona " &amp;lt;&amp;lt; n &amp;lt;&amp;lt; "\n";&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  static shared_ptr&amp;lt;Persona&amp;gt; Crear(int n) { &lt;br /&gt;    return shared_ptr&amp;lt;Persona&amp;gt;(new Persona(n));&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  shared_ptr&amp;lt;Persona&amp;gt; a(new Persona(1));&lt;br /&gt;  shared_ptr&amp;lt;Persona&amp;gt; b = Persona::Crear(2);&lt;br /&gt;  shared_ptr&amp;lt;Persona&amp;gt; c;&lt;br /&gt;&lt;br /&gt;  cout &amp;lt;&amp;lt; "--- Aquí ambas personas existen ---\n";&lt;br /&gt;&lt;br /&gt;  c = a; // Aquí c apunta a la persona 1&lt;br /&gt;  b = c; // Ahora b apuntará a la persona 1 (la persona 2 muere porque&lt;br /&gt;         // ya no existen referencias a ella)&lt;br /&gt;&lt;br /&gt;  cout &amp;lt;&amp;lt; "--- Aquí la persona 2 ya no existe ---\n";&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}        // Aquí muere la persona 1 (a, b, c apuntaban a ella)&lt;br /&gt;&lt;/pre&gt;La salida del anterior programa es esta:&lt;br /&gt;&lt;pre class="console"&gt;Nace la persona 1&lt;br /&gt;Nace la persona 2&lt;br /&gt;--- Aquí ambas personas existen ---&lt;br /&gt;Muere la persona 2&lt;br /&gt;--- Aquí la persona 2 ya no existe ---&lt;br /&gt;Muere la persona 1&lt;br /&gt;&lt;/pre&gt;Como puede ver, en el anterior programa se llama sólo dos veces a "new Persona" y dos veces al destructor ~Persona. No debemos preocuparnos por usar "delete", el shared_ptr&amp;lt;&amp;gt; hace todo por nosotros.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;¿Cómo hago para que la clase shared_ptr funcione en VS2008 SP1 Express?&lt;/b&gt; Debe definir _HAS_TR1 antes de incluir el archivo &amp;lt;memory&amp;gt;. Ejemplo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#ifdef _MSC_VER      // Si estamos usando el compilador de Microsoft&lt;br /&gt;  #define _HAS_TR1 1 // Esto hará que se incluyan las clases del TR1 (std::tr1)&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;#ifdef _MSC_VER&lt;br /&gt;  using namespace std::tr1; // para tener shared_ptr&amp;lt;&amp;gt; disponible&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;// Resto del ejemplo...&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-4303488601552155816?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/4303488601552155816/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=4303488601552155816' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/4303488601552155816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/4303488601552155816'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2010/05/shared-pointers-de-c0x.html' title='Shared Pointers de C++0x'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-9151549130027944942</id><published>2010-03-31T09:07:00.002-03:00</published><updated>2010-03-31T09:28:13.178-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++0x'/><title type='text'>C++0x Final Committee Draft (FCD)</title><content type='html'>Ya está disponible el documento N3092, &lt;em&gt;Programming Languages — C++, Final Committee Draft&lt;/em&gt;. Este documento es el que más podría corresponder al nuevo estándar ISO de C++ (lo que viene de acá a uno o dos años pueden ser correcciones menores):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf"&gt;http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Más información &lt;a href="http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/"&gt;acá&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-9151549130027944942?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/9151549130027944942/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=9151549130027944942' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/9151549130027944942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/9151549130027944942'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2010/03/c0x-final-committee-draft-fcd.html' title='C++0x Final Committee Draft (FCD)'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-1740419321130176820</id><published>2010-01-27T20:14:00.004-03:00</published><updated>2010-05-20T00:32:14.962-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='version'/><category scheme='http://www.blogger.com/atom/ns#' term='parser'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><title type='text'>STL string, parseando un número de versión</title><content type='html'>En esta ocasión vamos a ver cómo usar la clase &lt;em&gt;std::string&lt;/em&gt; para convertir una cadena de caracteres (como "1.2.3") en una clase "Version" que tenga una interfaz simple de utilizar (por ejemplo, que permita comparar versiones).&lt;br /&gt;&lt;br /&gt;Los pasos son simples:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;tenemos como entrada una cadena de caracteres,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;dividimos la cadena según el caracter '.' (punto),&lt;br /&gt;&lt;/li&gt;&lt;li&gt;convertimos cada parte a entero,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;guardamos cada número entero de forma ordenada en un vector.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;El punto 2 es en el cual nos vamos a enfocar más. &lt;em&gt;El código mostrado aquí es a modo de ejemplo, y está lejos de ser el más óptimo.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Antes de comenzar ¿Podemos usar &lt;a href="http://www.cplusplus.com/reference/clibrary/cstring/strcmp/"&gt;strcmp&lt;/a&gt; para comparar dos versiones?&lt;/b&gt; No, no podemos. Ejemplo: strcmp("1.9", "1.10") &amp;gt; 0, cuando en realidad la versión 1.9 es menor a 1.10.&lt;br /&gt;&lt;br /&gt;Imaginemos que tenemos una cadena: &lt;br /&gt;&lt;pre class="prettyprint"&gt;std::string ver = "1.10.2.3";&lt;br /&gt;&lt;/pre&gt;La clase &lt;a href="http://www.cplusplus.com/reference/string/string/"&gt;std::string&lt;/a&gt; tiene la función miembro &lt;a href="http://www.cplusplus.com/reference/string/string/find/"&gt;find&lt;/a&gt;, la cual podemos usar para buscar casi cualquier cosa dentro de la cadena. ¿Qué debemos buscar? Los puntos, sabiendo donde está cada punto, podemos ir recortando la cadena en sus distintas partes ("1", "10", "2", y "3"). Buscamos la ubicación del primer punto: &lt;br /&gt;&lt;pre class="prettyprint"&gt;size_t i = ver.find('.');&lt;br /&gt;&lt;br /&gt;if (i != std::string::npos)&lt;br /&gt;  std::printf("El punto fue encontrado en la posición %d\n", i);&lt;br /&gt;else&lt;br /&gt;  std::printf("No hay punto en la cadena\n");&lt;br /&gt;&lt;/pre&gt;Ejecutando el código anterior, deberíamos obtener el mensaje: &lt;br /&gt;&lt;pre&gt;El punto fue encontrado en la posición 1&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;¿Qué es &lt;a href="http://www.cplusplus.com/reference/clibrary/cstring/size_t/"&gt;size_t&lt;/a&gt;?&lt;/b&gt; Es como el tipo "unsigned int", el tipo de dato retornado por el operador &lt;a href="http://www.cppreference.com/wiki/keywords/sizeof"&gt;sizeof()&lt;/a&gt; y utilizado como índice en las funciones de std::string.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;¿Qué es &lt;a href="http://www.cplusplus.com/reference/string/string/npos/"&gt;std::string::npos&lt;/a&gt;?&lt;/b&gt; Es el máximo valor posible de un &lt;em&gt;size_t&lt;/em&gt; y se utiliza para indicar (en este caso) que la función &lt;em&gt;find&lt;/em&gt; falló (no encontró el punto).&lt;br /&gt;&lt;br /&gt;Una vez que tenemos la posición del punto, podemos obtener la porción de texto que contiene la primer cifra, para eso usamos la función miembro &lt;a href="http://www.cplusplus.com/reference/string/string/substr/"&gt;substr&lt;/a&gt;: &lt;br /&gt;&lt;pre class="prettyprint"&gt;std::string primer_cifra = ver.substr(0, i);&lt;br /&gt;&lt;/pre&gt;Esto significa: &lt;em&gt;che vos, función substr, devolveme el pedazo de cadena de caracteres que va desde el índice 0, y tiene una longitud de i-caracteres.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;El proceso puede ser repetido tantas veces como queramos para seguir obteniendo cifras. Por ejemplo, para la siguiente cifra debemos buscar (find) el siguiente punto, pero comenzando desde el que encontramos hace un rato: &lt;br /&gt;&lt;pre class="prettyprint"&gt;i++;     // ir a la posición siguiente del punto '.'&lt;br /&gt;size_t j = ver.find('.', i);&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;¿Qué es (o hace) el segundo argumento de find?&lt;/b&gt; Le indica a la función desde donde debe comenzar a buscar. La primera vez que usamos find este argumento no se especificó, porque por omisión toma el valor 0, es decir, buscar desde el inicio de la cadena.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;¿Por qué i++?&lt;/b&gt; Porque si comenzáramos a buscar un punto desde &lt;em&gt;i&lt;/em&gt;, nos devolvería la misma posición &lt;em&gt;i&lt;/em&gt; (porque justamente, en &lt;em&gt;i&lt;/em&gt;, está el primer punto que encontramos). Entonces debemos avanzar una posición.&lt;br /&gt;&lt;br /&gt;Ahora, debemos recortar la segunda cifra: &lt;br /&gt;&lt;pre class="prettyprint"&gt;std::string segunda_cifra = ver.substr(i, j-i);&lt;br /&gt;&lt;/pre&gt;La segunda cifra, comienza desde &lt;em&gt;i&lt;/em&gt; y tiene una longitud igual a &lt;em&gt;j-i&lt;/em&gt;. Para comprender esto, vea la siguiente figura:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_LUOxBrR4np4/S2DDl0pVkfI/AAAAAAAAAds/pDJ8xqGYqEE/s1600-h/std_string_indices.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="155" src="http://3.bp.blogspot.com/_LUOxBrR4np4/S2DDl0pVkfI/AAAAAAAAAds/pDJ8xqGYqEE/s400/std_string_indices.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;De esta forma, &lt;em&gt;ver.substr(i, j-i)&lt;/em&gt; nos devuelve la cadena "10". La versión completa del algoritmo puede quedar algo así:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;vector&amp;gt;  // Por std::vector&lt;br /&gt;#include &amp;lt;string&amp;gt;  // Por std::string&lt;br /&gt;#include &amp;lt;cstdlib&amp;gt; // Por std::strtol&lt;br /&gt;#include &amp;lt;cstdio&amp;gt;  // Por std::printf&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::string ver = "1.10.2.3";&lt;br /&gt;&lt;br /&gt;  // Vector con cada cifra.&lt;br /&gt;  // Luego del procesamiento esto debería ser = { 1, 10, 2, 3 }&lt;br /&gt;  std::vector&amp;lt;int&amp;gt; cifras;&lt;br /&gt;&lt;br /&gt;  size_t i = 0;   // Comenzamos desde i=0&lt;br /&gt;  size_t j = 0;&lt;br /&gt;&lt;br /&gt;  // Repetir hasta no llegar al final de la cadena&lt;br /&gt;  while (j != std::string::npos) {&lt;br /&gt;    // Buscar próximo punto&lt;br /&gt;    j = ver.find('.', i);&lt;br /&gt;&lt;br /&gt;    std::string cifra;&lt;br /&gt;&lt;br /&gt;    // Si se encontró un punto&lt;br /&gt;    if (j != std::string::npos) {&lt;br /&gt;      // Recortamos desde i hasta j&lt;br /&gt;      cifra = ver.substr(i, j-i);&lt;br /&gt;&lt;br /&gt;      // El nuevo comienzo para buscar puntos será "j+1"&lt;br /&gt;      i = j+1;&lt;br /&gt;    }&lt;br /&gt;    // Si no se encontró un punto&lt;br /&gt;    else {&lt;br /&gt;      // Recortamos desde "i" hasta el final de la cadena&lt;br /&gt;      cifra = ver.substr(i);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Obtener el valor entero de la cifra&lt;br /&gt;    int cifra_int = std::strtol(cifra.c_str(), NULL, 10);&lt;br /&gt;&lt;br /&gt;    // Agregar la cifra al vector&lt;br /&gt;    cifras.push_back(cifra_int);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  for (size_t i=0; i&amp;lt;cifras.size(); ++i)&lt;br /&gt;    printf("cifras[%d] = %d\n", i, cifras[i]);&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;La salida del anterior programa es:&lt;br /&gt;&lt;pre&gt;cifras[0] = 1&lt;br /&gt;cifras[1] = 10&lt;br /&gt;cifras[2] = 2&lt;br /&gt;cifras[3] = 3&lt;br /&gt;&lt;/pre&gt;Con este código, podríamos implementar una clase "Version" con la siguiente interfaz:&lt;br /&gt;&lt;pre class="prettyprint"&gt;class Version&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Version(const char*);&lt;br /&gt;  Version(const std::string&amp;amp;);&lt;br /&gt;&lt;br /&gt;  bool operator==(const Version&amp;amp; u) const;&lt;br /&gt;  bool operator&amp;lt;(const Version&amp;amp; u) const;&lt;br /&gt;  // ...&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;En un próximo post voy a colocar una posible implementación de la clase "Version".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-1740419321130176820?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/1740419321130176820/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=1740419321130176820' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/1740419321130176820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/1740419321130176820'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2010/01/stl-string-parseando-un-numero-de.html' title='STL string, parseando un número de versión'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_LUOxBrR4np4/S2DDl0pVkfI/AAAAAAAAAds/pDJ8xqGYqEE/s72-c/std_string_indices.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-8183254772973387343</id><published>2009-11-06T00:50:00.007-03:00</published><updated>2011-03-05T13:02:20.484-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scoped pointer'/><category scheme='http://www.blogger.com/atom/ns#' term='raii'/><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='leaks'/><title type='text'>Punteros por ámbito (scoped pointers)</title><content type='html'>C++ no tiene un &lt;a href="http://es.wikipedia.org/wiki/Recolector_de_basura"&gt;recolector de basura&lt;/a&gt;, &lt;a href="http://www.research.att.com/~bs/C++0xFAQ.html#gc-abi"&gt;aunque C++0x le va tomando el gustito&lt;/a&gt;, tenemos algunas opciones para liberarnos de liberar memoria, valga la redundancia.&lt;br /&gt;&lt;br /&gt;Imaginemos un código como el siguiente:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class A {&lt;br /&gt;public:&lt;br /&gt;  A()         { printf("A\n");    }&lt;br /&gt;  ~A()        { printf("~A\n");   }&lt;br /&gt;  void hola() { printf("hola\n"); }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  A* a = new A;&lt;br /&gt;  a-&amp;gt;hola();&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;El anterior programa, por más &lt;a href="http://en.wikipedia.org/wiki/Minimalism"&gt;minimalista&lt;/a&gt; que parezca, tiene un &lt;a href="http://en.wikipedia.org/wiki/Memory_leak"&gt;memory leak&lt;/a&gt;. Aunque los &lt;a href="http://en.wikipedia.org/wiki/Resource_(computer_science)"&gt;recursos&lt;/a&gt; suelen ser liberados por el mismo sistema operativo al finalizar el programa, si el proceso se ejecuta por mucho tiempo (e.j. un servicio que se ejecuta por días, semanas o meses dentro de un servidor), los recursos se van agotando poco a poco hasta que la computadora queda hecha una &lt;a href="http://es.wikipedia.org/wiki/Pasa"&gt;pasa&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Para arreglar el leak, deberíamos escribir:&lt;br /&gt;&lt;pre class="prettyprint"&gt;int main()&lt;br /&gt;{&lt;br /&gt;  A* a = new A;&lt;br /&gt;  a-&amp;gt;hola();&lt;br /&gt;  &lt;b&gt;delete a;&lt;/b&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;¿Cómo hacemos para liberar memoria sin llamar &lt;i&gt;delete&lt;/i&gt; nosotros mismos?&lt;/b&gt; Podemos crear una clase utilitaria que haga el trabajo por nosotros en su destructor. Por ejemplo, en el siguiente código veremos que el delete es llamado en el destructor de PunteroA:&lt;br /&gt;&lt;pre class="prettyprint"&gt;class PunteroA {&lt;br /&gt;  A* ptr;&lt;br /&gt;public:&lt;br /&gt;  PunteroA(A* p) { ptr = p; }&lt;br /&gt;  &lt;b&gt;~PunteroA()    { delete ptr; }&lt;/b&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  PunteroA a(new A);&lt;br /&gt;  a-&amp;gt;hola();          // error, "a" no es un puntero ni sobrecarga operator-&amp;gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;El anterior programa nos dará un error de compilación ya que el tipo PunteroA no soporta el operador flecha. Debemos agregarlo en la definición de la clase PunteroA:&lt;br /&gt;&lt;pre class="prettyprint"&gt;class PunteroA {&lt;br /&gt;  A* ptr;&lt;br /&gt;public:&lt;br /&gt;  PunteroA(A* p)  { ptr = p; }&lt;br /&gt;  ~PunteroA()     { delete ptr; }&lt;br /&gt;  &lt;b&gt;A* operator-&amp;gt;() { return ptr; }&lt;/b&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  PunteroA a(new A);&lt;br /&gt;  a-&amp;gt;hola();        // ahora sí, PunteroA::operator-&amp;gt;() nos devuelve&lt;br /&gt;                    // el verdadero puntero A* y A::hola() finalmente&lt;br /&gt;                    // es llamado&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;¿Cómo obtengo el A* desde un PunteroA?&lt;/b&gt; Debemos definir el operador de conversión hacia A*:&lt;br /&gt;&lt;pre class="prettyprint"&gt;class PunteroA {&lt;br /&gt;  A* ptr;&lt;br /&gt;public:&lt;br /&gt;  PunteroA(A* p)  { ptr = p; }&lt;br /&gt;  ~PunteroA()     { delete ptr; }&lt;br /&gt;  A* operator-&amp;gt;() { return ptr; }&lt;br /&gt;  &lt;b&gt;operator A*()   { return ptr; }&lt;/b&gt;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;Así podemos usar un PunteroA en funciones que reciban un A*. Ejemplo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;void func(A* a) { ... }&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  PunteroA a(new A);&lt;br /&gt;  func(a);&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Generalizando:&lt;/b&gt; Podemos generalizar nuestro PunteroA para cualquier tipo de dato:&lt;br /&gt;&lt;pre class="prettyprint"&gt;template&amp;lt;class T&amp;gt;&lt;br /&gt;class ScopedPointer {&lt;br /&gt;  T* ptr;&lt;br /&gt;public:&lt;br /&gt;  ScopedPointer(T* p) { ptr = p; }&lt;br /&gt;  ~ScopedPointer()    { delete ptr; }&lt;br /&gt;  &lt;br /&gt;  operator T*()       { return ptr; }&lt;br /&gt;  T* operator-&amp;gt;()     { return ptr; }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;Así podemos usar el mismo ScopedPointer para liberar instancias de cualquier clase:&lt;br /&gt;&lt;pre class="prettyprint"&gt;int main()&lt;br /&gt;{&lt;br /&gt;  ScopedPointer&amp;lt;A&amp;gt; a(new A);&lt;br /&gt;  ScopedPointer&amp;lt;B&amp;gt; b(new B);&lt;br /&gt;  a-&amp;gt;hola();&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;¿Y si quiero liberar otro tipo de recurso?&lt;/b&gt; Si el recurso no es memoria, y es liberado con otra función en vez de delete, podemos generalizar nuestro ScopedPointer con un nuevo parámetro de template llamado &lt;i&gt;Destroyer&lt;/i&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;struct DefaultDestroyer {&lt;br /&gt;  template&amp;lt;class T&amp;gt;&lt;br /&gt;  static void &lt;b&gt;free&lt;/b&gt;(T* ptr) { delete ptr; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template&amp;lt;class T, class &lt;b&gt;Destroyer&lt;/b&gt; = DefaultDestroyer&amp;gt;&lt;br /&gt;class ScopedPointer {&lt;br /&gt;  T* ptr;&lt;br /&gt;public:&lt;br /&gt;  ScopedPointer(T* p) { ptr = p; }&lt;br /&gt;  ~ScopedPointer()    { &lt;b&gt;Destroyer::free(ptr);&lt;/b&gt; }&lt;br /&gt;  &lt;br /&gt;  operator T*()       { return ptr; }&lt;br /&gt;  T* operator-&amp;gt;()     { return ptr; }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;En este caso, el destructor ~ScopedPointer llama a la función estática Destroyer::free. Esta función básicamente puede hacer lo que nosotros queramos. Podría ser útil para liberar ficheros o cualquier otro tipo de recurso:&lt;br /&gt;&lt;pre class="prettyprint"&gt;struct FileDestroyer {&lt;br /&gt;  static void free(FILE* ptr) { fclose(ptr); }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  ScopedPointer&amp;lt;FILE, FileDestroyer&amp;gt; file(fopen("hola.txt", "rt"));&lt;br /&gt;  char buf[256];&lt;br /&gt;  fread(buf, 1, 256, file);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;¿No existen punteros de este tipo ya implementados?&lt;/b&gt; &lt;a href="http://www.boost.org/"&gt;Boost&lt;/a&gt; tiene su propio &lt;a href="http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/scoped_ptr.htm"&gt;scoped_ptr&lt;/a&gt;. También existen punteros más avanzados que cuentan referencias, como los &lt;a href="http://en.wikipedia.org/wiki/C%2B%2B0x#General-purpose_smart_pointers"&gt;smart pointers&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-8183254772973387343?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/8183254772973387343/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=8183254772973387343' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/8183254772973387343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/8183254772973387343'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2009/11/punteros-por-ambito-scoped-pointers.html' title='Punteros por ámbito (scoped pointers)'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-3720137353173753110</id><published>2009-10-18T12:21:00.005-03:00</published><updated>2010-05-20T00:50:15.520-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='conceptos'/><category scheme='http://www.blogger.com/atom/ns#' term='interfaces'/><title type='text'>Interfaces vs. Conceptos</title><content type='html'>¿Qué son los conceptos? Vamos a ver con un simple ejemplo, cómo podemos hacer una equivalencia entre las conocidas &lt;a href="http://en.wikipedia.org/wiki/Interface_(computer_science)"&gt;interfaces&lt;/a&gt; y los &lt;a href="http://en.wikipedia.org/wiki/Concept_(generic_programming)"&gt;conceptos&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Imaginen esta "interfaz" (clase abstracta):&lt;br /&gt;&lt;pre class="prettyprint"&gt;class IPortero {&lt;br /&gt;public:&lt;br /&gt;  virtual IPortero() { }&lt;br /&gt;  virtual void ir_a_piso(int piso) = 0;&lt;br /&gt;  virtual int piso_destino() = 0;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;Tenemos otra clase Ascensor que podemos "personalizar" con nuestro propio portero, así nuestra implementación de portero puede hacer &lt;a href="http://es.wikipedia.org/wiki/Ascensor#Algoritmos_de_Maniobras"&gt;lo que se le de la gana&lt;/a&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;class Ascensor {&lt;br /&gt;  IPortero* m_portero;&lt;br /&gt;public:&lt;br /&gt;  Ascensor(IPortero* portero) {&lt;br /&gt;    m_portero = portero;&lt;br /&gt;  }&lt;br /&gt;  void apretaron_boton_en_piso(int piso) {&lt;br /&gt;    m_portero-&gt;ir_a_piso(piso);&lt;br /&gt;    mover_ascensor(m_portero-&gt;piso_destino());&lt;br /&gt;  }&lt;br /&gt;  void mover_ascensor(int piso) { ... }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;Con programación genérica, podemos reformular la interfaz convirtiéndola en un "concepto" y la clase Ascensor en una clase plantilla:&lt;br /&gt;&lt;pre class="prettyprint"&gt;template&amp;lt;class TipoPortero&amp;gt;&lt;br /&gt;class Ascensor {&lt;br /&gt;  TipoPortero m_portero;&lt;br /&gt;public:&lt;br /&gt;  Ascensor() { }&lt;br /&gt;  void apretaron_boton_en_piso(int piso) {&lt;br /&gt;    m_portero.ir_a_piso(piso);&lt;br /&gt;    mover_ascensor(m_portero.piso_destino());&lt;br /&gt;  }&lt;br /&gt;  void mover_ascensor(int piso) { ... }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;La pregunta es, &lt;em&gt;¿qué demonios es TipoPortero?&lt;/em&gt;. La respuesta es sencilla: TipoPortero puede ser cualquier tipo de dato que cumpla los siguientes requisitos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tenga un constructor por omisión (que se pueda construir un nuevo TipoPortero sin argumentos, o sea, &lt;em&gt;TipoPortero()&lt;/em&gt;).&lt;br /&gt;&lt;li&gt;Tenga una función miembro &lt;em&gt;TipoPortero::ir_a_piso(int)&lt;/em&gt;, la cual recibe un "int" (o cualquier tipo de dato que se pueda construir desde un "int" implícitamente).&lt;br /&gt;&lt;li&gt;Y otra función miembro &lt;em&gt;TipoPortero::piso_destino()&lt;/em&gt; que devuelve un entero.&lt;br /&gt;&lt;/ul&gt;&lt;p&gt;&lt;b&gt;¿Cómo especificamos la "interfaz" o los "requerimientos" de un concepto?&lt;/b&gt; Sencillamente no se puede, &lt;a href="http://cmasomenos.blogspot.com/2009/07/c0x-no-va-tener-conceptos.html"&gt;C++0x iba a soportar esto&lt;/a&gt;, pero ya no. Hoy en día la mejor respuesta es usar algunos comentarios en la clase Ascensor que especifiquen qué espera en sus parámetros de template. En este aspecto se podría decir que IPortero es mejor porque especifica explícitamente lo que el portero tiene que hacer (funciones a implementar, etc.).&lt;p&gt;&lt;b&gt;¿Qué ventaja tiene el concepto con respecto a las interfaces?&lt;/b&gt; La clase genérica Ascensor ahora tiene el mismo portero adentro suyo (no un puntero a la interfaz). Las llamadas a las funciones miembro &lt;em&gt;ir_a_piso&lt;/em&gt; y &lt;em&gt;piso_destino&lt;/em&gt; son llamadas directas (no tienen el &lt;a href="http://en.wikipedia.org/wiki/Virtual_method_table#Efficiency"&gt;overhead de una llamada a una función virtual&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-3720137353173753110?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/3720137353173753110/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=3720137353173753110' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/3720137353173753110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/3720137353173753110'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2009/10/interfaces-vs-conceptos.html' title='Interfaces vs. Conceptos'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-4223411900424123051</id><published>2009-10-17T21:50:00.002-03:00</published><updated>2010-05-20T00:53:11.079-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='optimización'/><category scheme='http://www.blogger.com/atom/ns#' term='clases'/><category scheme='http://www.blogger.com/atom/ns#' term='abstracción'/><title type='text'>Clases que "desaparecen" luego de compilar</title><content type='html'>La magia de C++ es que, una vez compilado el código, algunas clases pueden desaparecer por completo (principalmente las que se usan en &lt;a href="http://en.wikipedia.org/wiki/Call_stack"&gt;stack&lt;/a&gt;). O sea, aunque las clases abstraen al programador de los detalles de implementación, al final, el código termina siendo tan óptimo como si la clase no fuera utilizada en un principio.&lt;br /&gt;&lt;br /&gt;Un ejemplo. Teniendo la siguiente clase Acumulador:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;&lt;br /&gt;class Acumulador {&lt;br /&gt;  int v;&lt;br /&gt;public:&lt;br /&gt;  Acumulador()         { v = 0;                   }&lt;br /&gt;  ~Acumulador()        { std::printf("%d\n", v);  }&lt;br /&gt;  void acumular(int x) { v += x;                  }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;Un código como el siguiente:&lt;br /&gt;&lt;pre class="prettyprint"&gt;{&lt;br /&gt;  Acumulador acum;&lt;br /&gt;  acum.acumular(2);&lt;br /&gt;  acum.acumular(4);&lt;br /&gt;  acum.acumular(10);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Al compilarlo (optimizándolo), el código equivale a exactamente esto:&lt;br /&gt;&lt;pre class="prettyprint"&gt;{&lt;br /&gt;  int v = 0;&lt;br /&gt;  v += 2;&lt;br /&gt;  v += 4;&lt;br /&gt;  v += 10;&lt;br /&gt;  std::printf("%d\n", v);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;La clase Acumulador ya no existe. Obtenemos el código más óptimo posible: sin llamadas a la función "acumular", ni ningún byte extra de memoria (Acumulador ocupa lo mismo de memoria que ocupa un "int").&lt;br /&gt;&lt;br /&gt;Este ejemplo no ayuda a ver grandes ventajas, pero si el constructor y el destructor hacen tareas complicadas, y las funciones miembros también, el resultado puede llevarnos a dos puntos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Nos abstrae de la complejidad de la implementación (e.j. &lt;em&gt;para qué quiero saber cómo se acumula si sólo quiero acumular&lt;/em&gt;)&lt;br /&gt;&lt;li&gt;Obtenemos código tan óptimo como si no hubiéramos usado la abstracción (e.j. &lt;em&gt;las operaciones se acercan al hardware tanto como sea posible&lt;/em&gt;).&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-4223411900424123051?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/4223411900424123051/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=4223411900424123051' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/4223411900424123051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/4223411900424123051'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2009/10/clases-que-desaparecen-luego-de.html' title='Clases que &quot;desaparecen&quot; luego de compilar'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-5568618301379444386</id><published>2009-07-23T11:10:00.015-03:00</published><updated>2010-03-04T23:31:53.087-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++0x'/><category scheme='http://www.blogger.com/atom/ns#' term='conceptos'/><title type='text'>C++0x no va a tener "conceptos"</title><content type='html'>En la última reunión del &lt;a href="http://www.open-std.org/jtc1/sc22/wg21/"&gt;ISO C++ Standards Committe&lt;/a&gt;e decidieron quitar los "&lt;a href="http://en.wikipedia.org/wiki/Concepts_%28C%2B%2B0x%29"&gt;conceptos&lt;/a&gt;" del próximo estándar de &lt;a href="http://en.wikipedia.org/wiki/C%2B%2B0x"&gt;C++&lt;/a&gt; (que en realidad, en vez de C++0x va a ser C++1x y chirola). &lt;a href="http://www.ddj.com/architect/218600111"&gt;Un artículo de Bjarne Stroustrup&lt;/a&gt; habla al respecto:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;[...] Básicamente, los "conceptos" tenían como meta hacer de la programación genérica algo más accesible a la mayoría de los programadores, pero esa meta ha sido para mí (Stroustrup) seriamente comprometida: En vez de hacer la programación genérica más accesible, los "conceptos" se fueron convirtiendo en otra herramienta más en las manos de los expertos (únicamente).&lt;br /&gt;[...]&lt;br /&gt;Para resumir y de alguna forma simplificar, he afirmado que:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Los "conceptos" como están actualmente definidos son muy difíciles de utilizar, lo que los llevará al desuso, dando la posibilidad a un desuso de los &lt;em&gt;templates&lt;/em&gt; mismos y a la adopción completa de C++0x.&lt;/li&gt;&lt;li&gt;Un pequeño conjunto de simplificaciones [&lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2906.pdf"&gt;BS2009&lt;/a&gt;] pueden dejar a los "conceptos" lo suficientemente aceptables como para salir acorde a las fechas planificadas para C++0x o con sólo un retraso menor.&lt;br /&gt;&lt;/ul&gt;[...] &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-5568618301379444386?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/5568618301379444386/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=5568618301379444386' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/5568618301379444386'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/5568618301379444386'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2009/07/c0x-no-va-tener-conceptos.html' title='C++0x no va a tener &quot;conceptos&quot;'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-6330679899391627832</id><published>2009-07-12T14:01:00.004-03:00</published><updated>2010-05-20T01:05:24.576-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='vector'/><category scheme='http://www.blogger.com/atom/ns#' term='buffer'/><category scheme='http://www.blogger.com/atom/ns#' term='stl'/><title type='text'>STL vector en vez de los clásicos buffers de C</title><content type='html'>Algunas veces tenemos que crear buffers temporales. Por ejemplo, la función &lt;a href="http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/"&gt;sprintf&lt;/a&gt; necesita de un buffer para poder dejar la cadena resultante. Ejemplo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;char buf[256];&lt;br /&gt;sprintf(buf, "%d", 12345);&lt;br /&gt;// usar "buf"...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Si queremos mantener el buffer en heap:&lt;br /&gt;&lt;pre class="prettyprint"&gt;char* buf = malloc(256);&lt;br /&gt;sprintf(buf, "%d", 12345);&lt;br /&gt;// usar "buf"...&lt;br /&gt;free(buf);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En C++ podríamos hacer uso de los operadores new[]/delete[]:&lt;br /&gt;&lt;pre class="prettyprint"&gt;char* buf = new char[256];&lt;br /&gt;sprintf(buf, "%d", 12345);&lt;br /&gt;// usar "buf"...&lt;br /&gt;delete[] buf;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pero es aconsejable evitar la creación de arreglos con new[], y en su lugar hacer uso de &lt;a href="http://www.cplusplus.com/reference/stl/vector/"&gt;std::vector&lt;/a&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;std::vector&amp;lt;char&amp;gt; buf(256);&lt;br /&gt;sprintf(&amp;amp;buf[0], "%d", 12345);&lt;br /&gt;// usar "&amp;amp;buf[0]" en vez de "buf"...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-6330679899391627832?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/6330679899391627832/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=6330679899391627832' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6330679899391627832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6330679899391627832'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2009/07/stl-vector-en-vez-de-los-clasicos.html' title='STL vector en vez de los clásicos buffers de C'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-6782049308008941622</id><published>2009-03-21T08:44:00.003-03:00</published><updated>2010-05-20T00:49:58.436-03:00</updated><title type='text'>STL for_each</title><content type='html'>Para recorrer un arreglo de C, podemos utilizar punteros. Comenzamos apuntando al primer elemento y frenamos una vez procesado el último elemento:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  int array[] = { 5, 3, 4, 9, 1 };&lt;br /&gt;  int array_size = sizeof(array) / sizeof(int); // cantidad de elementos de "array"&lt;br /&gt;  int *array_begin = array;                     // comienzo del array&lt;br /&gt;  int *array_end = array+array_size;            // final del array (+un elemento)&lt;br /&gt;  int *it;                                      // el iterator&lt;br /&gt;&lt;br /&gt;  for (it = array_begin;  it != array_end;  ++it) {&lt;br /&gt;    printf("%d\n", *it);&lt;br /&gt;  }&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Hay que tener en cuenta que array_end es igual a &amp;array[5]. Sabiendo que sólo podemos acceder a los elementos desde array[0] a array[4], decimos que array[5] está más allá del último elemento del arreglo, es decir, &amp;array[5] es la posición de memoria que ya no es parte del mismo arreglo (de ahí "it != array_end" significa "mientras nos encontremos dentro del arreglo").&lt;br /&gt;&lt;br /&gt;¿Cómo recorrer un &lt;a href="http://www.sgi.com/tech/stl/Container.html"&gt;contenedor&lt;/a&gt; de la STL? La idea es similar, sólo que en vez de usar punteros utilizamos iteradores, y observe como la sintaxis del &lt;i&gt;for&lt;/i&gt; es exactamente la misma. (nota: en este caso utilizamos un &lt;a href="http://www.sgi.com/tech/stl/Vector.html"&gt;vector&lt;/a&gt;).&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  vector&amp;lt;int&amp;gt; array;&lt;br /&gt;  array.push_back(5);&lt;br /&gt;  array.push_back(3);&lt;br /&gt;  array.push_back(4);&lt;br /&gt;  array.push_back(9);&lt;br /&gt;  array.push_back(1);&lt;br /&gt;&lt;br /&gt;  vector&amp;lt;int&amp;gt;::iterator it;&lt;br /&gt;&lt;br /&gt;  for (it = array.begin();  it != array.end();  ++it) {&lt;br /&gt;    cout &amp;lt;&amp;lt; *it &amp;lt;&amp;lt; endl;&lt;br /&gt;  }&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;¿Cómo recorrer un contenedor STL con el algoritmo &lt;a href="http://www.sgi.com/tech/stl/for_each.html"&gt;for_each&lt;/a&gt;? (nota: lo siguiente también se puede hacer con &lt;a href="http://www.sgi.com/tech/stl/copy.html"&gt;copy&lt;/a&gt; y &lt;a href="http://www.sgi.com/tech/stl/ostream_iterator.html"&gt;ostream_iterator&lt;/a&gt;)&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;void print_element(int a) { cout &amp;lt;&amp;lt; *it &amp;lt;&amp;lt; endl; }&lt;br /&gt;    &lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  vector&amp;lt;int&amp;gt; array;&lt;br /&gt;  array.push_back(5);&lt;br /&gt;  array.push_back(3);&lt;br /&gt;  array.push_back(4);&lt;br /&gt;  array.push_back(9);&lt;br /&gt;  array.push_back(1);&lt;br /&gt;&lt;br /&gt;  for_each(array.begin(), array.end(), print_element);&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;La función pasada como tercer parámetro a &lt;i&gt;for_each&lt;/i&gt; es llamada por cada elemento del arreglo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;template&lt;typename InputIterator, typename Function&gt;&lt;br /&gt;Function for_each(InputIterator first, InputIterator last, Function f)&lt;br /&gt;{&lt;br /&gt;  for (; first != last; ++first)&lt;br /&gt;    f(*first);&lt;br /&gt;  return f;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;¿Por qué &lt;i&gt;for_each&lt;/i&gt; devuelve la función? Principalmente porque la función "f" podría no ser una función! Podría ser un &lt;a href="http://www.sgi.com/tech/stl/functors.html"&gt;functor&lt;/a&gt; (objeto función), es decir, una instancia de una clase que tiene sobrecargado el &lt;i&gt;operator()&lt;/i&gt; (llamada a función). Pero este tema se merece su propio post.&lt;br /&gt;&lt;br /&gt;¿Se puede usar el algoritmo for_each para los arreglos de C? Sí.&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;void print_element(int a) { printf("%d\n", a); }&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  int array[] = { 5, 3, 4, 9, 1 };&lt;br /&gt;  int array_size = sizeof(array) / sizeof(int); // cantidad de elementos de "array"&lt;br /&gt;  int *array_begin = array;                     // comienzo del array&lt;br /&gt;  int *array_end = array+array_size;            // final del array (un elemento más)&lt;br /&gt;&lt;br /&gt;  for_each(array_begin, array_end, print_element);&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-6782049308008941622?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/6782049308008941622/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=6782049308008941622' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6782049308008941622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6782049308008941622'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2009/03/stl-foreach.html' title='STL for_each'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-8017999882907419607</id><published>2008-12-08T14:18:00.009-02:00</published><updated>2010-05-20T00:49:44.066-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='algoritmo'/><category scheme='http://www.blogger.com/atom/ns#' term='stl'/><title type='text'>STL generate</title><content type='html'>Si usted tiene una función que genera números/valores/instancias (ej: un generador de números aleatorios, o identificadores) puede usar el algoritmo &lt;a href="http://www.cplusplus.com/reference/algorithm/generate.html"&gt;generate&lt;/a&gt; de la &lt;a href="http://www.sgi.com/tech/stl/"&gt;STL&lt;/a&gt; para crear una secuencia de objetos. Por ejemplo, para generar 100 números (pseudo)aleatorios de 0 a 1:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;&lt;br /&gt;double uniform_random()&lt;br /&gt;{&lt;br /&gt;  return (rand() % 10001) / 10000.0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::vector&amp;lt;double&amp;gt; v(100);&lt;br /&gt;  std::generate(v.begin(), v.end(), uniform_random);&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;El algoritmo &lt;em&gt;generate&lt;/em&gt; recibe dos iteradores (inicio y fin), y llama a la función especificada para cada una de las posiciones que recorre:&lt;br /&gt;&lt;pre class="prettyprint"&gt;template&amp;lt;typename ForwardIterator, typename Generator&amp;gt;&lt;br /&gt;void generate(ForwardIterator first, ForwardIterator last,&lt;br /&gt;              Generator gen)&lt;br /&gt;{&lt;br /&gt;  for (; first != last; ++first)&lt;br /&gt;    *first = gen();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Los algoritmos de la STL son genéricos porque utilizan la &lt;a href="http://en.wikipedia.org/wiki/Pointer_(computing)#C_and_C.2B.2B"&gt;aritmética de punteros&lt;/a&gt;. Los iteradores sobrecargan los operadores para poder ser utilizados como punteros. Así un algoritmo puede ser utilizado con los contenedores de la STL (&lt;a href="http://www.sgi.com/tech/stl/Vector.html"&gt;vector&lt;/a&gt;) o con los viejos y tan queridos arreglos (y punteros) de C:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;&lt;br /&gt;double uniform_random()&lt;br /&gt;{&lt;br /&gt;  return (rand() % 10001) / 10000.0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  double v[100];&lt;br /&gt;  std::generate(v, v+100, uniform_random);&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-8017999882907419607?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/8017999882907419607/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=8017999882907419607' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/8017999882907419607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/8017999882907419607'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2008/12/stl-generate.html' title='STL generate'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-4871056687622874222</id><published>2008-08-19T09:34:00.034-03:00</published><updated>2010-05-20T00:48:31.184-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='operadores'/><category scheme='http://www.blogger.com/atom/ns#' term='optimización'/><category scheme='http://www.blogger.com/atom/ns#' term='ensamblador'/><title type='text'>¿Preincrementar o postincrementar?</title><content type='html'>Hace mucho que quería escribir un post tan inútil como este. La duda que siempre me pasaba por la cabeza era la siguiente: ¿Será exactamente el mismo código ensamblador el que genera el compilador cuando utilizamos el preincremento o el postincremento (sin utilizar el valor de retorno)? Tenía la seguridad de que así debía ser (una optimización tan básica no podía ser dejada de lado), pero me faltaban las pruebas (en ensamblador) para verificarlo.&lt;br /&gt;&lt;br /&gt;Recordando un poco, el preincremento&lt;br /&gt;&lt;pre class="prettyprint"&gt;int a = 0;&lt;br /&gt;int b = ++a;&lt;br /&gt;&lt;/pre&gt;hace &lt;i&gt;a=1&lt;/i&gt; y &lt;i&gt;b=1&lt;/i&gt;, mientras que el postincremento&lt;br /&gt;&lt;pre class="prettyprint"&gt;int a = 0;&lt;br /&gt;int b = a++;&lt;br /&gt;&lt;/pre&gt;hace &lt;i&gt;a=1&lt;/i&gt; y &lt;i&gt;b=0&lt;/i&gt;, esto significa que &lt;i&gt;b&lt;/i&gt; obtuvo el valor de &lt;i&gt;a&lt;/i&gt; anterior al incremento.&lt;br /&gt;&lt;br /&gt;Aquí &lt;i&gt;estamos utilizando&lt;/i&gt; el valor de retorno del operador incremento. El código ensamblador &lt;i&gt;es distinto&lt;/i&gt; para cada caso. Vamos a echarle una mirada (antes le recomiendo ver &lt;a href="http://www.unixwiz.net/techtips/win32-callconv-asm.html"&gt;este excelente artículo&lt;/a&gt; para comprender más sobre el stack y las convenciones de llamadas). En el preincremento el código ensamblador (generado por GCC 3.4.5 para i386) es:&lt;br /&gt;&lt;pre class="prettyprint"&gt;subl  $8, %esp          // reservamos 8 bytes en el &lt;a href="http://en.wikipedia.org/wiki/Call_stack"&gt;stack&lt;/a&gt; (para variables locales)&lt;br /&gt;movl  $0, -4(%ebp)      // a   = 0&lt;br /&gt;leal  -4(%ebp), %eax    // eax = &amp;amp;a&lt;br /&gt;incl  (%eax)            // *eax= (*eax) + 1&lt;br /&gt;movl  -4(%ebp), %eax    // eax = a&lt;br /&gt;movl  %eax, -8(%ebp)    // b   = eax&lt;br /&gt;&lt;/pre&gt;En el postincremento&lt;br /&gt;&lt;pre class="prettyprint"&gt;subl  $8, %esp          // reservamos 8 bytes en el stack&lt;br /&gt;movl  $0, -4(%ebp)      // a   = 0&lt;br /&gt;movl  -4(%ebp), %edx    // edx = a&lt;br /&gt;leal  -4(%ebp), %eax    // eax = &amp;amp;a&lt;br /&gt;incl  (%eax)            // *eax= (*eax) + 1&lt;br /&gt;movl  %edx, -8(%ebp)    // b   = edx&lt;/pre&gt;donde se ve que el registro edx se utiliza para guardar el valor que tenía &lt;i&gt;a&lt;/i&gt; antes del incremento para luego asignárselo a &lt;i&gt;b&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Pero la pregunta original es, ¿qué pasa si &lt;b&gt;no&lt;/b&gt; usamos el valor de retorno? ¿el código de ++i o i++ es igual? Debería serlo, y de hecho, lo es. Pero como veremos más abajo, esto sólo se cumple si utilizamos tipos de datos &lt;i&gt;built-in&lt;/i&gt; (int, double, long, etc.). Miremos el siguiente código:&lt;br /&gt;&lt;pre class="prettyprint"&gt;void func() { }&lt;br /&gt;void pre () { for (int c=0; c&amp;lt;8; ++c) { func(); } }&lt;br /&gt;void post() { for (int c=0; c&amp;lt;8; c++) { func(); } }&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  pre();&lt;br /&gt;  post();&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Básico, un &lt;i&gt;for&lt;/i&gt; pero con las dos variantes posible de incremento. El código generado para ambos casos (tanto para la función &lt;i&gt;pre&lt;/i&gt; como &lt;i&gt;post&lt;/i&gt;) es el siguiente:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;  pushl %ebp              // guardar el viejo puntero a la base del stack&lt;br /&gt;  movl  %esp, %ebp        // establecer la nueva base del stack&lt;br /&gt;  subl  $4, %esp          // guardar 4 bytes en el stack (para variables locales)&lt;br /&gt;  movl  $0, -4(%ebp)      // c = 0&lt;br /&gt;L3:&lt;br /&gt;  cmpl  $7, -4(%ebp)&lt;br /&gt;  jg    L2                // si c &amp;gt; 7 entonces ir a L2&lt;br /&gt;  call  _func             // llamar a la función func()&lt;br /&gt;  leal  -4(%ebp), %eax    // eax = &amp;amp;c&lt;br /&gt;  incl  (%eax)            // *eax= (*eax) + 1&lt;br /&gt;  jmp   L3                // repetir yendo a L3&lt;br /&gt;L2:&lt;br /&gt;  leave                   // restaurar la base del stack (popl %ebp)&lt;br /&gt;  ret                     // retornar al punto de llamada&lt;br /&gt;&lt;/pre&gt;Realmente es indiferente usar cualquiera de los dos tipos de incremento, salvo, en los tipos definidos por el usuario.  C++ ofrece un soporte para tipos de usuario igual a los built-in (bueno, no del todo, pero &lt;a href="http://www.artima.com/cppsource/cpp0xP.html"&gt;lo están solucionando&lt;/a&gt;). Nos da la posibilidad de sobrecargar los operadores de nuestros propios tipos (clases). Por ejemplo:&lt;br /&gt;&lt;pre class="prettyprint"&gt;class tipo {&lt;br /&gt;  int x;&lt;br /&gt;public:&lt;br /&gt;  tipo(int y) : x(y) { }&lt;br /&gt;  tipo(const tipo&amp;amp; y) : x(y.x) { }&lt;br /&gt;  // preincremento&lt;br /&gt;  tipo&amp;amp; operator++() {&lt;br /&gt;    ++x;&lt;br /&gt;    return *this;&lt;br /&gt;  }&lt;br /&gt;  // postincremento&lt;br /&gt;  tipo operator++(int) {&lt;br /&gt;    tipo tmp(*this);&lt;br /&gt;    ++x;&lt;br /&gt;    return tmp;&lt;br /&gt;  }&lt;br /&gt;  bool operator&amp;lt;(int y) const { return x &amp;lt; y; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void func() { }&lt;br /&gt;void pre()  { for (tipo c=0; c&amp;lt;8; ++c) { func(); } }&lt;br /&gt;void post() { for (tipo c=0; c&amp;lt;8; c++) { func(); } }&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  post();&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;No colocaré el código ensamblador por desbordar belleza, pero el código generado en este caso es distinto: cada incremento llama a la función correspondiente a su operador. Esto es debido a que ambas implementaciones varían considerablemente. Por ejemplo, el postincremento necesita de una instancia extra de &lt;i&gt;tipo&lt;/i&gt; para poder devolver el anterior valor de &lt;i&gt;this&lt;/i&gt;, en cambio, el preincremento devuelve una referencia al mismo &lt;i&gt;this&lt;/i&gt; (sin necesidad de hacer una copia).&lt;br /&gt;&lt;br /&gt;Como dato curioso, algo interesante ocurre al utilizar las optimizaciones del GCC. Si compilamos este último programa con el parámetro -O3, vamos a ver que todas las funciones correspondientes a la clase &lt;i&gt;tipo&lt;/i&gt; desaparecen, y todo el código resultantes es &lt;i&gt;inline&lt;/i&gt;, dando como resultado un código tan óptimo como si hubiéramos utilizado un &lt;i&gt;int&lt;/i&gt; en vez de nuestra clase &lt;i&gt;tipo&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;¿Cómo obtengo el código ensamblador desde un archivo C/C++?&lt;/b&gt;&lt;br /&gt;Con el compilador &lt;i&gt;gcc&lt;/i&gt;, hay que utilizar el parámetro -S: &lt;br /&gt;&lt;pre class="console"&gt;g++ -S -o archivo.s -c archivo.cpp&lt;br /&gt;&lt;/pre&gt;En &lt;i&gt;archivo.s&lt;/i&gt; queda el código ensamblador (sintaxis &lt;a href="http://www.google.com.ar/search?q=AT%26T+Assembly+Syntax"&gt;AT&amp;amp;T&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-4871056687622874222?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/4871056687622874222/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=4871056687622874222' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/4871056687622874222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/4871056687622874222'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2008/08/preincrementar-o-postincrementar.html' title='¿Preincrementar o postincrementar?'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-1607696112932338525</id><published>2008-06-24T15:28:00.040-03:00</published><updated>2010-05-20T00:48:02.131-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='auto_ptr'/><category scheme='http://www.blogger.com/atom/ns#' term='exception'/><title type='text'>Excepciones, RAII y auto_ptr</title><content type='html'>Una de las mejores formas de realizar un control de errores es por medio de excepciones. Lamentablemente, si no se toman las precauciones adecuadas, se pueden obtener &lt;a href="http://en.wikipedia.org/wiki/Handle_leak"&gt;leaks&lt;/a&gt; de algunos recursos. Por ejemplo, imagine el siguiente caso:&lt;pre class="prettyprint"&gt;int main()&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;try {&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;char *ptr = new char[256];&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;double *matrix = new double[100000*100000]; // 74 Gigabytes&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;// ...&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;delete matrix;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;delete ptr;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;} catch (const std::bad_alloc&amp;amp; e) {&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;std::cout &amp;lt;&amp;lt; "No hay memoria suficiente" &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Aquí, con el segundo &lt;em&gt;new&lt;/em&gt; una excepción &lt;em&gt;bad_alloc&lt;/em&gt; es lanzada. El problema es que la memoria asignada con el primer &lt;em&gt;new&lt;/em&gt; nadie la libera. Esto es un &lt;a href="http://en.wikipedia.org/wiki/Memory_leak"&gt;memory leak&lt;/a&gt;. Una opción para solucionarlo es mediante un bloque &lt;a href="http://www.research.att.com/~bs/bs_faq2.html#finally"&gt;finally&lt;/a&gt; "a la Java":&lt;br /&gt;&lt;pre class="prettyprint"&gt;int main()&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;char *ptr = NULL;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;double *matrix = NULL;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;try {&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;ptr = new char[256];&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;matrix = new double[100000*100000];&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;// ...&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;delete matrix;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;delete ptr;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;} catch (...) { // finally&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;if (matrix) delete matrix;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;if (ptr) delete ptr;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Claro que esto no hace al manejo de errores una tarea transparente.&lt;br /&gt;&lt;br /&gt;En C++ se puede utilizar la técnica &lt;a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization"&gt;RAII&lt;/a&gt; (la adquisición de recursos está en la inicialización), lo que ayuda a evitar &lt;em&gt;leaks&lt;/em&gt;. La idea básica detrás de esto es que los constructores obtengan recursos, y los destructores los liberen. Al ocurrir una excepción, se van llamando los destructores de los objetos creados.&lt;br /&gt;&lt;br /&gt;Para solucionar nuestro problema, podemos utilizar la clase &lt;em&gt;auto_ptr&lt;/em&gt; que se encuentra en &amp;lt;memory&amp;gt;. Un &lt;em&gt;auto_ptr&lt;/em&gt; guarda un puntero que es liberado automáticamente en el destructor.&lt;pre class="prettyprint"&gt;int main()&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;try {&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;std::auto_ptr&amp;lt;char&amp;gt; ptr(new char[256]);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;std::auto_ptr&amp;lt;double&amp;gt; matrix(new double[100000*100000]);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;// ...&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;} catch (const std::bad_alloc&amp;amp; e) {&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;std::cout &amp;lt;&amp;lt; "No hay memoria suficiente" &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Los &lt;em&gt;delete&lt;/em&gt;s no son necesarios. Al salir del &lt;a href="http://en.wikipedia.org/wiki/Scope_%28programming%29"&gt;ámbito&lt;/a&gt; del bloque &lt;em&gt;try&lt;/em&gt;, ya sea normalmente o por excepción, se llamará al destructor de los &lt;em&gt;auto_ptr&lt;/em&gt;s creados, así no se incurre en ningún tipo de &lt;em&gt;leak&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Advertencia&lt;/b&gt;: Los &lt;em&gt;auto_ptr&lt;/em&gt; deben ser utilizados sabiendo cuál es su verdadero funcionamiento: La copia de un &lt;em&gt;auto_ptr&lt;/em&gt; a otro no los deja equivalentes. La última copia se queda con el puntero, los demás lo van perdiendo, y el &lt;em&gt;delete&lt;/em&gt; lo invoca el último &lt;em&gt;auto_ptr&lt;/em&gt; destruido. Por ejemplo:&lt;pre class="prettyprint"&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;std::auto_ptr&amp;lt;Persona&amp;gt; otra_persona;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;std::auto_ptr&amp;lt;Persona&amp;gt; una_persona(new Persona);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;otra_persona = una_persona;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;// ahora "una_persona" apunta a NULL&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;}&lt;br /&gt;} // aquí la persona es destruida&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Pregunta&lt;/b&gt;: ¿Por qué no usar objetos alojados en el &lt;a href="http://en.wikipedia.org/wiki/Call_stack"&gt;stack&lt;/a&gt; en vez del &lt;a href="http://en.wikipedia.org/wiki/Dynamic_memory_allocation"&gt;heap&lt;/a&gt; para evitar los &lt;em&gt;leaks&lt;/em&gt;? Porque el &lt;em&gt;stack&lt;/em&gt; es mucho más pequeño. Por ejemplo, el siguiente código provoca un &lt;a href="http://en.wikipedia.org/wiki/SIGSEGV"&gt;SIGSEGV&lt;/a&gt; ya que el arreglo no entra en el &lt;em&gt;stack&lt;/em&gt;:&lt;pre class="prettyprint"&gt;double matrix[1000000];&lt;/pre&gt;Pero sí entra en el &lt;em&gt;heap&lt;/em&gt;:&lt;pre class="prettyprint"&gt;double *matrix = new double[1000000]; // 7.6 Megabytes&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-1607696112932338525?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/1607696112932338525/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=1607696112932338525' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/1607696112932338525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/1607696112932338525'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2008/06/excepciones-raii-y-autoptr.html' title='Excepciones, RAII y auto_ptr'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-9220110933263076450</id><published>2008-05-10T00:30:00.002-03:00</published><updated>2008-05-10T00:33:59.797-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gcc'/><category scheme='http://www.blogger.com/atom/ns#' term='compilar'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Compilando archivos</title><content type='html'>Suponiendo que conoce qué es un archivo de &lt;a href="http://es.wikipedia.org/wiki/C%C3%B3digo_fuente"&gt;código fuente&lt;/a&gt;, &lt;a href="http://es.wikipedia.org/wiki/C%C3%B3digo_objeto"&gt;código objeto&lt;/a&gt;, un &lt;a href="http://es.wikipedia.org/wiki/Ejecutable"&gt;ejecutable&lt;/a&gt; &lt;a href="http://es.wikipedia.org/wiki/EXE"&gt;&lt;b&gt;.exe&lt;/b&gt;&lt;/a&gt;, y el &lt;a href="http://es.wikipedia.org/wiki/C%C3%B3digo_m%C3%A1quina"&gt;código máquina&lt;/a&gt;; voy a pasar a explicar algunos comandos del &lt;a href="http://es.wikipedia.org/wiki/GCC"&gt;GCC&lt;/a&gt; para compilar.&lt;br /&gt;&lt;br /&gt;Retomando la idea del &lt;a href="http://cmasomenos.blogspot.com/2008/03/medir-el-tiempo-de-una-rutina.html"&gt;anterior post&lt;/a&gt;, imagínese que creamos un archivo &lt;a href="http://davidcapello.googlepages.com/timemark.h"&gt;timemark.h&lt;/a&gt; para darle un poco de portabilidad a todo este asunto de medir el desempeño de una rutina. Las declaraciones de timemark.h pueden ser usadas para crear un pequeño programa &lt;a href="http://davidcapello.googlepages.com/ejemplo1.c"&gt;ejemplo1.c&lt;/a&gt; que sea independiente de la plataforma (por lo menos entre Windows y GNU/Linux).&lt;br /&gt;&lt;br /&gt;Vamos a probar algunas operaciones sobre la línea de comandos para ver cómo compilar este archivo. Inicialmente, la opción más sencilla es utilizar directamente "gcc ejemplo1.c", esto nos da como resultado el archivo "a.exe" o "a.out". Veamos (teniendo &lt;em&gt;timemark.h&lt;/em&gt; y &lt;em&gt;ejemplo1.c&lt;/em&gt; en un directorio &lt;em&gt;C:\ejemplo1&lt;/em&gt;):&lt;br /&gt;&lt;pre class="source-code"&gt;C:\ejemplo1&amp;gt;gcc ejemplo1.c&lt;br /&gt;C:/Temp/ccMjdaaa.o:ejemplo1.c:(.text+0x31): undefined reference to `get_timemark'&lt;br /&gt;C:/Temp/ccMjdaaa.o:ejemplo1.c:(.text+0x3c): undefined reference to `get_timemark'&lt;br /&gt;C:/Temp/ccMjdaaa.o:ejemplo1.c:(.text+0x4e): undefined reference to `timemark_diff'&lt;br /&gt;collect2: ld returned 1 exit status&lt;br /&gt;&lt;/pre&gt;Como podrá ver, recibimos un error por las funciones no definidas &lt;em&gt;get_timermark&lt;/em&gt; y &lt;em&gt;timemark_diff&lt;/em&gt;. Esto se debe a que utilizando solamente "gcc ejemplo1.c", se intenta enlazar el código de ese único archivo en el ejecutable. Tenemos algunas opciones intermedias antes de crear el .exe final. Por ejemplo, podemos crear un archivo que contenga el código objeto ya compilado (pero únicamente del archivo en cuestión &lt;em&gt;ejemplo1.c&lt;/em&gt;):&lt;br /&gt;&lt;pre class="source-code"&gt;C:\ejemplo1&amp;gt;gcc -o ejemplo1.o -c ejemplo1.c&lt;br /&gt;&lt;/pre&gt;Así obtenemos el &lt;em&gt;ejemplo1.o&lt;/em&gt; (código objeto). En este caso no recibimos errores ya que &lt;em&gt;ejemplo1.o&lt;/em&gt; hace referencias a las funciones &lt;em&gt;get_timermark&lt;/em&gt; y &lt;em&gt;timemark_diff&lt;/em&gt;, pero no necesita su implementación específica. Cuando creamos el ejecutable final (&lt;em&gt;.exe&lt;/em&gt;) es cuando realmente necesitamos el código de todas las funciones invocadas.&lt;br /&gt;&lt;br /&gt;El archivo que falta es &lt;a href="http://davidcapello.googlepages.com/timemark.c"&gt;timemark.c&lt;/a&gt;. Del mismo modo, podemos compilarlo con el comando:&lt;br /&gt;&lt;pre class="source-code"&gt;C:\ejemplo1&amp;gt;gcc -o timemark.o -c timemark.c&lt;br /&gt;&lt;/pre&gt;Ahora resta unir ambos archivos objetos en un único ejecutable, con un único punto de acceso (&lt;em&gt;main&lt;/em&gt;):&lt;br /&gt;&lt;pre class="source-code"&gt;C:\ejemplo1&amp;gt;gcc -o ejemplo.exe ejemplo1.o timemark.o&lt;br /&gt;&lt;/pre&gt;Y listo. Por ahora, lo aprendido son estos dos comandos:&lt;br /&gt;&lt;pre class="source-code"&gt;gcc -o archivo.o -c archivo.c&lt;br /&gt;gcc -o archivo.exe archivo1.o archivo2.o archivo3.o ...&lt;br /&gt;&lt;/pre&gt;El primero compila el código fuente para generar un archivo objeto, y el segundo comando reune (enlaza, &lt;em&gt;linkea&lt;/em&gt;) el grupo de archivos objetos en un ejecutable único.&lt;br /&gt;&lt;br /&gt;De todas formas, es bastante tedioso escribir estos comandos cada vez que queremos compilar. Para resolver el problema podemos utilizar los llamados Makefiles. Claro, lo más interesante queda para un futuro post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-9220110933263076450?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/9220110933263076450/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=9220110933263076450' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/9220110933263076450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/9220110933263076450'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2008/05/compilando-archivos.html' title='Compilando archivos'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-2720258185855146665</id><published>2008-03-01T11:59:00.010-02:00</published><updated>2010-05-20T00:43:26.849-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tiempo'/><category scheme='http://www.blogger.com/atom/ns#' term='optimización'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Medir el tiempo de una rutina</title><content type='html'>¿Alguna vez se preocupó por la velocidad con la que corre su programa? ¿No? Entonces usted es un candidato perfecto para jugar al &lt;a href="http://en.wikipedia.org/wiki/Java_%28board_game%29"&gt;Java&lt;/a&gt;. En caso contrario, voy a explicarle un pequeño código que utilizaremos en próximas entregas para medir el tiempo de ejecución de determinadas rutinas.&lt;br /&gt;&lt;br /&gt;Ya lo dijo &lt;a href="http://shreevatsa.wordpress.com/2008/05/16/premature-optimization-is-the-root-of-all-evil/"&gt;alguien&lt;/a&gt;: "La optimización prematura es la raíz de todos los males". No hay nada más cierto, aunque también es verdad que hacer algo simple de la peor forma posible, es la causa de &lt;a href="http://www.urbandictionary.com/define.php?term=pain+in+the+ass"&gt;otros grandes males&lt;/a&gt;. Con esto quiero decir que debería intentar hacer las cosas de la forma más simple y más óptima que usted conozca (dándole mayor importancia a la simplicidad del código); luego se preocupa por "darle velocidad" a la rutina que provoca el cuello de botella (en próximos posts veremos cómo usar &lt;em&gt;gprof&lt;/em&gt; para detectarlo).&lt;br /&gt;&lt;br /&gt;La forma de calcular el tiempo de CPU que toma una función es muy simple:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;tomamos el valor del reloj antes de realizar la llamada (&lt;em&gt;t_ini&lt;/em&gt;),&lt;/li&gt;&lt;li&gt;llamamos a la rutina en cuestión, y&lt;/li&gt;&lt;li&gt;tomamos nuevamente el valor del reloj (&lt;em&gt;t_fin&lt;/em&gt;).&lt;/li&gt;&lt;/ul&gt;La diferencia entre &lt;em&gt;t_fin - t_ini&lt;/em&gt; nos da el total de tiempo que tomó: 1) hacer la llamada a la rutina, 2) que esta haga su trabajo, 3) que devuelva el resultado.&lt;br /&gt;&lt;br /&gt;Ahora hay algunos pequeños detalles de implementación. Por ejemplo, ¿qué función usar para tomar el tiempo del reloj? Y más importante, ¿qué precisión obtenemos con dicha función?&lt;br /&gt;&lt;br /&gt;Para tomar el tiempo podemos usar la rutina &lt;a href="http://www.cplusplus.com/clock"&gt;clock()&lt;/a&gt;, que devuelve el tiempo &lt;em&gt;aproximado&lt;/em&gt; de CPU que transcurrió desde que nuestro programa fue iniciado, dicho tiempo representado en un valor de tipo &lt;a href="http://www.cplusplus.com/clock_t"&gt;clock_t&lt;/a&gt;: un valor entero que indica una cantidad de "tics" de reloj.&lt;br /&gt;&lt;br /&gt;La precisión que tenemos con dicha rutina es de &lt;a href="http://www.cplusplus.com/CLOCKS_PER_SEC"&gt;CLOCKS_PER_SEC&lt;/a&gt; (tics de reloj por segundo), lo que significa que por cada segundo que pasa, la función &lt;em&gt;clock()&lt;/em&gt; nos devolverá CLOCKS_PER_SEC unidades más que el valor anterior. En MinGW, CLOCKS_PER_SEC es igual a 1000, pero es mejor no fiarse de esto, ya que en otras plataformas dicho valor varía. Inclusive, según POSIX, la constante CLOCKS_PER_SEC debería ser 1000000.&lt;br /&gt;&lt;br /&gt;Veamos algo de código:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;time.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;clock_t t_ini, t_fin;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;double secs;&lt;br /&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;t_ini = clock();&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;/* ...hacer algo... */&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;t_fin = clock();&lt;br /&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;printf("%.16g milisegundos\n", secs * 1000.0);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Con esto podemos medir cuántos milisegundos demoró &lt;em&gt;"hacer algo"&lt;/em&gt;. Todo parece muy bonito hasta que nos damos cuenta de dos grandes problemas:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Tomar una medida única y aislada es igual que tomar un número completamente aleatorio y mostrarlo (no es una &lt;a href="http://es.wikipedia.org/wiki/Muestra_estad%C3%ADstica"&gt;muestra representativa&lt;/a&gt;). Es mejor repetir las mediciones unas cuantas veces (y hablo del orden de las 100, o 100000, o 1e32 veces), y luego sacar un promedio de todo.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;La función &lt;span style="font-style: italic;"&gt;clock()&lt;/span&gt; no llega a tener una precisión  ni de 10 milisegundos (aunque CLOCS_PER_SEC sea 1000 o más).&lt;/li&gt;&lt;/ol&gt;Una vez dicho esto, el código de arriba no sirve ni para &lt;a href="http://es.wikipedia.org/wiki/Papel_higi%C3%A9nico"&gt;limpiarse&lt;/a&gt; los &lt;a href="http://es.wikipedia.org/wiki/Traste"&gt;trastes&lt;/a&gt;... Así que tenemos que buscar una función con mayor precisión, y además, promediar varias muestras.&lt;br /&gt;&lt;br /&gt;Existen otras alternativas como la función &lt;a href="http://www.freebsd.org/cgi/man.cgi?query=gettimeofday"&gt;gettimeofday&lt;/a&gt;, pero bajo Windows sufre del mismo problema de precisión que &lt;em&gt;clock()&lt;/em&gt;. Igualmente en Linux funciona perfectamente, así que vale la pena tener en cuenta este código:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;time.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/time.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* retorna "a - b" en segundos */&lt;br /&gt;double timeval_diff(struct timeval *a, struct timeval *b)&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;(double)(a-&amp;gt;tv_sec + (double)a-&amp;gt;tv_usec/1000000) -&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;(double)(b-&amp;gt;tv_sec + (double)b-&amp;gt;tv_usec/1000000);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;struct timeval t_ini, t_fin;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;double secs;&lt;br /&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;gettimeofday(&amp;amp;t_ini, NULL);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;/* ...hacer algo... */&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;gettimeofday(&amp;amp;t_fin, NULL);&lt;br /&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;secs = timeval_diff(&amp;amp;t_fin, &amp;amp;t_ini);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;printf("%.16g milliseconds\n", secs * 1000.0);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Como puede ver la estructura &lt;em&gt;timeval&lt;/em&gt; contiene dos campos, segundos y microsegundos transcurridos (tv_sec y tv_usec respectivamente), por lo tanto ofrece una precisión de microsegundos. De todas formas, como decía esto en Windows no sirve y la razón es sencilla, en la misma &lt;a href="http://msdn2.microsoft.com/en-us/library/ms725496%28VS.85%29.aspx"&gt;MSDN&lt;/a&gt; explican que el temporizador del sistema corre aproximadamente a unos 10 milisegundos, por lo tanto, cualquier función que lo utilice nos estará dando la misma asquerosa precisión (inclusive al utilizar &lt;a href="http://www.google.com.ar/search?q=GetSystemTimeAsFileTime+msdn"&gt;GetSystemTimeAsFileTime&lt;/a&gt; y &lt;a href="http://www.google.com.ar/search?q=FILETIME+msdn"&gt;FILETIME&lt;/a&gt;). Por lo tanto la solución es utilizar lo que se conoce en el mundo de Windows como el "contador de rendimiento de alta resolución" (&lt;em&gt;high-resolution performance counter&lt;/em&gt;):&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* retorna "a - b" en segundos */&lt;br /&gt;double performancecounter_diff(LARGE_INTEGER *a, LARGE_INTEGER *b)&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;LARGE_INTEGER freq;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;QueryPerformanceFrequency(&amp;amp;freq);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return (double)(a-&amp;gt;QuadPart - b-&amp;gt;QuadPart) / (double)freq.QuadPart;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;LARGE_INTEGER t_ini, t_fin;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;double secs;&lt;br /&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;QueryPerformanceCounter(&amp;amp;t_ini);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;/* ...hacer algo... */&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;QueryPerformanceCounter(&amp;amp;t_fin);&lt;br /&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;secs = performancecounter_diff(&amp;amp;t_fin, &amp;amp;t_ini);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;printf("%.16g milliseconds\n", secs * 1000.0);&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;return 0;&lt;br /&gt;}&lt;/pre&gt;En este caso, imagine que &lt;a href="http://www.google.com.ar/search?q=QueryPerformanceCounter+msdn"&gt;QueryPerformanceCounter&lt;/a&gt; es como &lt;em&gt;clock()&lt;/em&gt; y &lt;a href="http://www.google.com.ar/search?q=QueryPerformanceFrequency+msdn"&gt;QueryPerformanceFrequency&lt;/a&gt; es como CLOCKS_PER_SEC. Es decir, la primera función nos da el valor del contador, y la segunda su frecuencia (en ciclos por segundo, &lt;a href="http://en.wikipedia.org/wiki/Hertz"&gt;hertz&lt;/a&gt;). Cabe aclarar que un &lt;a href="http://www.google.com.ar/search?q=LARGE_INTEGER+msdn"&gt;LARGE_INTEGER&lt;/a&gt; es una forma de representar un entero de 64 bits por medio de una unión (&lt;em&gt;union&lt;/em&gt;).&lt;br /&gt;&lt;br /&gt;Como tarea al lector, si es que existe alguno, le queda hacer una versión "portable" (entre Windows y Linux) para medir el rendimiento (con unos cuantos &lt;em&gt;#ifdef WIN32&lt;/em&gt; y &lt;em&gt;#endif&lt;/em&gt; sería suficiente).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;18 de Marzo del 2008&lt;/span&gt;: acá transcribo una macro que me pasó el amigo &lt;a href="http://www.carlosbecker.com.ar/"&gt;Carlos Becker&lt;/a&gt; para medir el tiempo de una rutina en Linux mediante &lt;a href="http://www.tin.org/bin/man.cgi?section=3&amp;topic=clock_gettime"&gt;clock_gettime&lt;/a&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#define TIME_THIS(X) \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;{ \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;struct timespec ts1, ts2; \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;clock_gettime( CLOCK_REALTIME, &amp;amp;ts1 ); \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;X; \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;clock_gettime( CLOCK_REALTIME, &amp;amp;ts2 ); \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;printf( #X " demora: %f\n", \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;(float) ( 1.0*(1.0*ts2.tv_nsec - ts1.tv_nsec*1.0)*1e-9 \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;+ 1.0*ts2.tv_sec - 1.0*ts1.tv_sec ) ); \&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;/* podemos usarla así */&lt;br /&gt;{&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;double x, y, z;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;x = 2.0;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;y = 4.0;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;TIME_THIS(z = sqrt(x*x + y*y));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Lo que da como resultado:&lt;br /&gt;&lt;pre class="prettyprint"&gt;z = sqrt(x*x + y*y) demora: 0.015164&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-2720258185855146665?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/2720258185855146665/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=2720258185855146665' title='13 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/2720258185855146665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/2720258185855146665'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2008/03/medir-el-tiempo-de-una-rutina.html' title='Medir el tiempo de una rutina'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4295741868585735005.post-6099656894518733137</id><published>2008-02-17T16:55:00.008-02:00</published><updated>2011-05-21T09:23:41.437-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='gcc'/><category scheme='http://www.blogger.com/atom/ns#' term='instalación'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Conseguir un compilador</title><content type='html'>&lt;blockquote&gt;&lt;b&gt;Editado 21 de mayo 2011&lt;/b&gt;: Este post se encuentra aquí sólo a fines históricos, ahora usted puede usar el &lt;a href="http://sourceforge.net/projects/mingw/files/Automated%20MinGW%20Installer/mingw-get-inst"&gt;instalador automático de MinGW&lt;/a&gt;.&lt;br /&gt;&lt;p&gt;&lt;b&gt;Editado 9 de septiembre 2010&lt;/b&gt;: Aunque este post contiene información útil de cómo instalar MinGW con gcc 3.4, tal vez prefiera antes probar este &lt;a href="http://cmasomenos.blogspot.com/2010/06/descargar-mingw-con-gcc-45.html"&gt;nuevo post sobre cómo descargar MinGW con gcc 4.5 de forma automática&lt;/a&gt;.&lt;br /&gt;&lt;/blockquote&gt;&lt;p&gt;En este blog vamos a hablar sobre los lenguajes de programación C y C++, y cómo usar software GNU para hacer aplicaciones. También voy a tratar de investigar algo de ensamblador.&lt;br /&gt;&lt;p&gt;De todas formas, para evitar hacer un primer post completamente inútil "de presentación", voy a pasar a explicarles cómo pueden instalar un compilador gratuito en Windows desde cero, y hacer un pequeño programa &lt;span style="font-style: italic;"&gt;"Hola Mundo"&lt;/span&gt; sin pensar mucho (eso sí, van a tener que leer un poco). El proceso para Linux es más sencillo, ya que el compilador suele venir instalado por defecto en la mayoría de las distribuciones.&lt;br /&gt;&lt;p&gt;Primero, algunas definiciones importantes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.mingw.org/" style="font-weight: bold;"&gt;MinGW&lt;/a&gt;: Un conjunto de programas y bibliotecas que permiten crear aplicaciones para Windows.&lt;/li&gt;&lt;li&gt;&lt;a href="http://gcc.gnu.org/" style="font-weight: bold;"&gt;GCC&lt;/a&gt;: El compilador. Transforma código escrito en C/C++ a un archivo ejecutable (.exe). En realidad hace miles de maravillas más, pero por ahora nos vamos a quedar con esta definición.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;MSYS&lt;/span&gt;: Es un conjunto mínimo de programas para poder ejecutar scripts &lt;span style="font-style: italic;"&gt;"a la"&lt;/span&gt; Unix. Además incluye una terminal que emula un pequeño entorno GNU/Linux.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.gnu.org/software/emacs/" style="font-weight: bold;"&gt;Emacs&lt;/a&gt;: La madre de los editores de texto. Alguna vez dije que era una porquería o muy complicado, y que conviene usar editores como el &lt;a href="http://sourceforge.net/projects/rhide"&gt;RHIDE&lt;/a&gt; o &lt;a href="http://setedit.sourceforge.net/"&gt;Setedit&lt;/a&gt;. Bueno, la cosa es que con "&lt;span style="font-style: italic;"&gt;un poco&lt;/span&gt;" de práctica uno comprende el poder de esta herramienta.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;make&lt;/span&gt;: Un programa que puede compilar muchos archivos y linkearlos en un ejecutable de forma automatizada (siempre y cuando le escribamos un archivo con las órdenes adecuadas). Generalmente los programadores están acostumbrados a utilizar un &lt;a href="http://es.wikipedia.org/wiki/Entorno_de_desarrollo_integrado"&gt;IDE&lt;/a&gt; (como el &lt;a href="http://www.bloodshed.net/devcpp.html"&gt;DevC++&lt;/a&gt;) que maneje el proyecto, calcule las dependencias entre archivos, compile todo lo necesario, linkee, ejecute y depure. Si bien esto es cómodo, espero poder enseñarles a automatizar la compilación y liberarlos de un determinado IDE para compilar los programas.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;cmd.exe&lt;/span&gt;: Es la línea de comandos de Windows. Si nunca lo utilizó, es hora que se ponga a usarlo. Para iniciar la línea de comandos debe ir al menú "Inicio/Ejecutar..." e introducir "cmd". ¿Cómo se usa? Bueno, &lt;a href="http://www.google.com.ar/search?q=introduccion+al+shell+de+comandos+cmd.exe"&gt;empiece a buscar...&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Ahora nos dedicaremos a instalar el MinGW, para eso debe comenzar a bajarse los siguientes archivos (si no sabe &lt;a href="http://www.7-zip.org/"&gt;cómo descomprimir un archivo .tar.gz...&lt;/a&gt;):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://downloads.sourceforge.net/mingw/mingw-runtime-3.13.tar.gz?download"&gt;mingw-runtime-3.13.tar.gz&lt;/a&gt;: Los archivos de cabecera y bibliotecas estándares (stdio.h, math.h, libc, libm, etc.)    &lt;/li&gt;&lt;li&gt;&lt;a href="http://downloads.sourceforge.net/mingw/w32api-3.10.tar.gz?download"&gt;w32api-3.10.tar.gz&lt;/a&gt;: Archivos de cabecera del API de Win32&lt;/li&gt;&lt;li&gt;&lt;a href="http://downloads.sourceforge.net/mingw/gcc-core-3.4.5-20060117-1.tar.gz?download"&gt;gcc-core-3.4.5-20060117-1.tar.gz&lt;/a&gt;: El preprocesador de C y el compilador de C&lt;/li&gt;&lt;li&gt;&lt;a href="http://downloads.sourceforge.net/mingw/gcc-g++-3.4.5-20060117-1.tar.gz?download"&gt;gcc-g++-3.4.5-20060117-1.tar.gz&lt;/a&gt;: El compilador de C++ y los archivos de cabecera de C++&lt;/li&gt;&lt;li&gt;&lt;a href="http://downloads.sourceforge.net/mingw/binutils-2.17.50-20060824-1.tar.gz?download"&gt;binutils-2.17.50-20060824-1.tar.gz&lt;/a&gt;: Varios programas utilitarios que sirve para diferentes propósitos (ej: quitar símbolos de depuración con &lt;span style="font-style: italic;"&gt;strip&lt;/span&gt;, convertir direcciones a líneas de código fuente con &lt;span style="font-style: italic;"&gt;addr2line&lt;/span&gt;, procesar la información de &lt;a href="http://en.wikipedia.org/wiki/Performance_analysis"&gt;rendimiento&lt;/a&gt; con &lt;span style="font-style: italic;"&gt;gprof&lt;/span&gt;, crear librerías con &lt;span style="font-style: italic;"&gt;ar&lt;/span&gt;, compilar los archivos de recursos de Windows con &lt;span style="font-style: italic;"&gt;windres&lt;/span&gt;, etc.).&lt;/li&gt;&lt;li&gt;&lt;a href="http://downloads.sourceforge.net/mingw/mingw32-make-3.81-2.tar.gz?download"&gt;mingw32-make-3.81-2.tar.gz&lt;/a&gt;: La utilidad &lt;span style="font-style: italic;"&gt;make&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://downloads.sourceforge.net/mingw/gdb-5.2.1-1.exe?download"&gt;gdb-5.2.1-1.exe&lt;/a&gt;: El depurador de código&lt;/li&gt;&lt;/ul&gt;Una vez que consiga todos estos archivos, debe crear una carpeta C:\MinGW (le recomiendo esa ubicación) y descomprimir todo ahí mismo. Para instalar el depurador (gdb) deberá ejecutar el instalador, seguir los pasos, y colocar como carpeta de instalación "C:\MinGW".&lt;br /&gt;&lt;p&gt;Una vez instalado todo, usted ya está en condiciones para compilar código en C o C++. Antes verifique que en dicha carpeta tiene una estructura de directorios como la siguiente:&lt;br /&gt;&lt;pre class="console"&gt;C:\MinGW&lt;br /&gt;  bin\&lt;br /&gt;  doc\&lt;br /&gt;  include\&lt;br /&gt;  info\&lt;br /&gt;  lib\&lt;br /&gt;  libexec\&lt;br /&gt;  man\&lt;br /&gt;  mingw32\&lt;br /&gt;&lt;/pre&gt;Si así es, significa que todo salió bien (bueno, tampoco descomprimir unos archivos es algo tan complicado).&lt;br /&gt;&lt;p&gt;Para estar seguros que el compilador funcione, vamos a crear el programa de prueba por excelencia, el "Hola Mundo". Abra el bloc de notas (Inicio/Ejecutar/notepad) y escriba en un archivo el siguiente código:&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;  printf("Hola Mundo\n");&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Guarde el archivo como "&lt;span style="font-style: italic;"&gt;C:\MinGW\hola.c&lt;/span&gt;". Ahora abra la línea de comandos &lt;span style="font-weight: bold;"&gt;cmd.exe&lt;/span&gt;, y ahí mismo ejecute los siguientes comandos:&lt;br /&gt;&lt;pre class="console"&gt;cd C:\MinGW&lt;br /&gt;set PATH=C:\MinGW\bin;%PATH%&lt;br /&gt;gcc hola.c&lt;br /&gt;&lt;/pre&gt;Verá que el archivo "&lt;span style="font-style: italic;"&gt;a.exe&lt;/span&gt;" se crea en el directorio C:\MinGW. Si ejecuta el programa &lt;span style="font-weight: bold;"&gt;a.exe&lt;/span&gt; visualizará en la salida de la consola el mensaje más estúpido jamás escrito: "&lt;span style="font-style: italic;"&gt;Hola Mundo&lt;/span&gt;"&lt;br /&gt;&lt;pre class="console"&gt;C:\MinGW&amp;gt;a.exe&lt;br /&gt;Hola Mundo&lt;br /&gt;&lt;/pre&gt;A continuación le paso a explicar qué hicimos en esta ráfaga de pasos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"cd C:\MinGW" es para ubicarnos en el directorio donde se encuentra el archivo o proyecto que queremos compilar (si no sabía esto, es porque todavía no estuvo buscando cómo usar cmd.exe...).&lt;/li&gt;&lt;li&gt;"set PATH=C:\MinGW\bin;%PATH%" es un conjunto de varias cosas: "&lt;span style="font-style: italic;"&gt;PATH&lt;/span&gt;" es una variable de entorno que indica cuáles son los directorios donde podemos encontrar archivos ejecutables (archivos ejecutables como &lt;span style="font-style: italic;"&gt;gcc.exe&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;cpp.exe&lt;/span&gt;, etc.); "&lt;span style="font-style: italic;"&gt;set&lt;/span&gt;" es un comando del shell para cambiar el valor de una variable de entorno; y "&lt;span style="font-style: italic;"&gt;%PATH%&lt;/span&gt;" devuelve el valor de dicha variable de entorno. Por lo tanto, lo único que estamos haciendo aquí es agregar una nueva ruta (C:\MinGW\bin) a PATH para que el shell encuentre los archivos ejecutables que a nosotros nos interesa (el preprocesador, compilador, etc.). Si desea ver dónde busca el shell los archivos ejecutables actualmente, puede usar el siguiente comando: "&lt;span style="font-style: italic;"&gt;echo %PATH%&lt;/span&gt;"&lt;/li&gt;&lt;li&gt;"gcc hola.c" compila el programa "hola.c" y deja el resultado (&lt;span style="font-style: italic;"&gt;linkea&lt;/span&gt; o &lt;span style="font-style: italic;"&gt;linkedita&lt;/span&gt;) en un archivo llamado "a.exe" (o "a.out" en Linux). En otros posts veremos cómo podemos especificar un nombre distinto a este archivo de salida.&lt;/li&gt;&lt;/ul&gt;De todo lo visto, lo más molesto es la configuración de la variable de entorno, es decir, si pensamos compilar varias veces, cada vez que abramos un shell (cmd.exe) deberemos hacer un "set PATH=C:\MinGW\bin;%PATH%". Para evitar este paso tenemos dos opciones:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Si tiene accesos de Administrador, puede hacer click derecho sobre "Mi PC", "Propiedades", "Opciones Avanzadas", "Variables de Entorno" y modificar la variable PATH agregándole el valor "C:\MinGW\bin" (recuerde no tocar las demás rutas, además de agregar un ";" para separar las distintas rutas entre sí).&lt;/li&gt;&lt;li&gt;En otro caso, puede crearse un archivo de comandos por lotes mi-mingw.bat para iniciar el shell adecuadamente con el PATH ya configurado. Por ejemplo, un mi-mingw.bat posible podría ser:&lt;br /&gt;&lt;pre class="console"&gt;set PATH=C:\MinGW\bin;%PATH%&lt;br /&gt;start cmd.exe&lt;br /&gt;&lt;/pre&gt;Este archivo podemos dejarlo en el Escritorio y cada vez que tengamos ganas de compilar, con un simple doble click ya podemos empezar. Inclusive, en vez de iniciar "start cmd.exe" podríamos iniciar algún IDE o editor de texto como Emacs. Pero eso para otro post.&lt;/li&gt;&lt;/ol&gt;Bueno, por hoy me cansé. Cualquier problema o pregunta que tengan, los comentarios están abiertos (y bien moderados :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4295741868585735005-6099656894518733137?l=cmasomenos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cmasomenos.blogspot.com/feeds/6099656894518733137/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4295741868585735005&amp;postID=6099656894518733137' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6099656894518733137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4295741868585735005/posts/default/6099656894518733137'/><link rel='alternate' type='text/html' href='http://cmasomenos.blogspot.com/2008/02/conseguir-un-compilador.html' title='Conseguir un compilador'/><author><name>David Capello</name><uri>https://profiles.google.com/109465192499995663692</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-tAKufM0R6eE/AAAAAAAAAAI/AAAAAAAAAo0/9bl6zDlagbE/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry></feed>
