Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Loretz

#61
Programación C/C++ / Re: C sabiendo C++
8 Junio 2019, 07:09 AM
El C++ (el primer estándar 98) desciende, es un derivado, del C95 (C90 más las correcciones de 1995). Luego, el C99 y el C++11 son los dos derivados de ese mismo ancestro común, el C95. Entonces, esto quiere decir que el C++11, C++14, C++17 y C++20 son primos, primos 2dos, etc. del C99, tienen al C95 como abuelito en común.

En esta página hay una lista con incompatibilidades entre C++98 y C99:
http://david.tribble.com/text/cdiffs.htm

Por ejemplo, palabras clave del C++98 que no va a reconocer un compilador C99:

  • bool
  • catch
  • class
  • const_cast
  • delete
  • dynamic_cast
  • explicit
  • export
  • false
  • friend
  • mutable
  • namespace
  • new
  • operator
  • private
  • protected
  • public
  • reinterpret_cast
  • static_cast
  • template
  • this
  • throw
  • true
  • try
  • typeid
  • typename
  • using
  • virtual
  • wchar_t

Una lista completa de lo que hace que un programa C++ no compile en C es bastante extensa, los temas serían:


  • Uniones anónimas
  • clases
  • constructores y destructores
  • excepciones y bloques try/catch
  • linkeo de funciones externas (extern "C")
  • sobrecarga de funciones
  • funciones miembro
  • namespaces
  • operadores y funciones new / delete
  • sobrecarga de operadores
  • referencias
  • STL (biblioteca estándar C++)
  • clases y funciones template

#62
Yo creo que la idea de las enum class (scoped enumeration) es hacer que el código sea más seguro (reducir la probabilidad de bugs) al usar valores simbólicos (los enumerators), pero que ya no representan directamente números como antes.

Quiero decir, si se tiene enum class color {rojo, verde, azul}; queda claro que al decir "rojo" se está diciendo "color::rojo", y ya no, como era antes, el int 0.

Si lo que necesitas es una colección de constantes enteras, probablemente te convenga seguir usando las enum del viejo estilo, o quizá definir las constantes en algún namespace.

#63
Te paso una solución que creo que podrás acomodar a tu caso:

Código (cpp) [Seleccionar]
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

int main()
{
    std::string cadena{ "Una cadena bastante larga que va a ser dividida en segmentos "
                        "de seis caracteres cada uno, y lo que falte se completara con asteriscos." };

    // nuevo size de la cadena (multiplo de 6)
    auto res = std::div(cadena.size(), 6LL); // calcula cociente y resto.
    size_t newsize = 6LL * res.quot;
    newsize += (res.rem) ? 6LL : 0;
    cadena.resize(newsize, '*'); // de ser necesario se completa con asteriscos.

    // un vector de strings de 6 caracteres cada una:
    std::vector<std::string> v;
    for (auto i = 0LL; i < newsize / 6LL; ++i) {
        v.push_back(cadena.substr(6LL * i, 6LL));
    }

    // a ver...
    for (const auto& i : v) {
        std::cout << i << '\n';
    }
}

#64
Primero voy a hacer algunos comentarios morales:

Estás aprendiendo C++, entonces:

0) necesitas un buen libro.

1) no uses new (y no uses delete). Son mecanismos para situaciones excepcionales. En la vida real, cuando un experto los usa, debe dar explicaciones, convincentes.

2) no uses system(), menos en algo como system("cls"); Si estás intentando aprender el lenguaje, ¿cómo es que ya has aprendido los vicios de un mal programador de hace 30 años?

3) no uses std::endl;  no lo necesitas. Quizá, si en algún momento te encuentras en las fronteras de alguna sofisticada arquitectura concurrente, bueno, en ese momento supongo que ya sabrás. Mientras tanto sólo molesta.

4) no uses strcpy(), estás llamando a la desgracia. Pero de todos modos, así como en C++ no se usan punteros tampoco se usan arrays, así que obviamente strcpy no tiene ninguna razón de ser.

Y un comentario técnico:

Tu programa tiene dos errores:

1) La función de comparación (tu operator<()) no tiene en cuenta cuando las dos cadenas son iguales. Puedes probar con:
bool operator<(const Usuario& _thisUser, const Usuario& _otherUser) {
   return strcmp(_thisUser.nombre, _otherUser.nombre) < 0;
}




2) estás usando delete dos veces sobre el mismo puntero.

En esta porción del
Código (cpp) [Seleccionar]

       Usuario usuario;  ///< creas un Usuario
       // etcetera,,,
       usuarios.insert(usuario);   ///< insertas una copia de tu Usuario en el set.


El problema es que usuarios.insert() inserta una copia, y como no has definido qué es hacer una copia de un Usuario, el compilador ha sintetizado tanto el "copy constructor" como el "copy assignment operator", y en ese caso hace una "shallow copy" del puntero nombre.

Luego se está invocando delete[] dos veces sobre cada uno de los punteros. La primera vez cuando la variable local usuario sale de ámbito y la segunda vez cuando el set usuarios sale de ámbito (se invoca el destructor de sus elementos).
Puedes reemplazar tu destructor por este otro para ver que se está invocando dos veces delete[] para cada nombre:
Usuario::~Usuario() {
   std::cout << "delete[] " << nombre << '\n';
   //delete[] nombre;
}


Lectura:
https://en.cppreference.com/w/cpp/language/rule_of_three The rule of three/five/zero



#65
Sí, así es. Necesitas sobrecargar el "operator<"; también puedes usar una función objeto (function object) que defina cuando uno de esos tipos es "menor que" el otro, y también puedes crear el set usando una expresión lambda como función de comparación. Las tres son funcionalmente equivalentes.

Un std::set contiene un conjunto ordenado de claves únicas, es por eso que necesitas una función que sirva para las dos cosas, definir el orden y garantizar unicidad. El operator< define un "strict weak ordering" (googlear) que es lo que necesita un std::set para establecer orden y unicidad, que se obtiene a partir de la relación de equivalencia (que no la igualdad), obtenida a partir del mismo operator<.
#66
En C++ ya tienes un "diccionario", en la forma de un std::map. También, si no necesitas que se mantenga ordenado, la clase std::unordered_map es directamente una "hash table".

Va un ejemplo:

Código (cpp) [Seleccionar]
#include <map>
#include <string>
#include <iostream>
#include <functional>

int main()
{
     std::map<std::string, int> mi_map{ {"hola", 1}, {"chau", 2} };

    for (const auto& [k, v] : mi_map) {
        std::cout << "key == " << k << "; value == " << v << '\n';
    }

    // si solo se necesita calcular los hash:

    std::string hola{ "hola mundo!" };

    std::hash<std::string> hash_function;

    size_t el_hash = hash_function(hola);

    std::cout << "hash de \"hola mundo\" == " << el_hash << '\n';
}

#67
No se si será eso (tú sabrás), pero al compilador le resulta sospechoso, y por eso el primer warning, la asignación dentro del if:

if (gSuperficiesDeImagenes[imagen1] = NULL)

#68
Va en el ejemplo:

Código (cpp) [Seleccionar]
#include <iostream>

int main()
{
   char claveHabitacion[10][10] = { "ST1", "ST2", "ST3", "ST4", "ST5", "ST6", "ST7", "ST8", "ST9", "ST10" };

   char* pm;

   // pm = &claveHabitacion[9];
   /* el problema aquí es que &claveHabitacion[9] es de tipo char(*)[10]
      y no puede asignarse a un char*

      Pero puedes hacer:
   */

   pm = reinterpret_cast<char*>(&claveHabitacion[9]);

   std::cout << pm;
}


Pero ten presente que usar reinterpret_cast se entiende como cuando un yogur está de oferta dos horas antes del vencimiento, no sé si me explico.
#69
En la línea:
int (* pSumar) (int)(int) = sumar;
hay un error, debería ser:
int (*pSumar) (int, int) = &sumar; // el & delante no es extrictamente necesario pero conviene


CitarVale, entonces se aloja en una especie de registro...
Tampoco.

Como te decía RayR, la dirección de una función (no de una "función miembro", recuerdas?) suele estar en memoria de sólo lectura (que en inglés la vas a encontrar como "code segment" o "text segment"). Entonces, un puntero a función va a apuntar a esa parte de la memoria que no es stack ni heap, sino la parte donde está el código del programa cuando se carga en memoria.

En algún momento también se mencionó que los "string literals" ("hola mundo" por ejemplo) también estaban en un sector especial de memoria de solo lectura, el "data segment", que tampo es stack ni heap.

Con respecto a la Call Stak, Hay un artículo en Wikipedia que vale la pena ser leído:
https://en.wikipedia.org/wiki/Call_stack

Por si no quedara del todo claro, no hay que perder de vista que cuando se habla de la "memoria" se trata de la "virtual address space". Creo que aquí encontrarás respuesta a las dudas que ni siquiera sabías que debías tener:
https://en.wikipedia.org/wiki/Virtual_address_space

[Nota]
También es cierto que estas representaciones corresponden a un modelo, el "C Abstract Machine Model" [http://web.stanford.edu/group/sequoia/cgi-bin/book/export/html/15], que es un modelo abstracto que los compiladores se encargan de trasladar a la máquina real.
Habitualmente los microprocesadores suelen tener niveles de memoria caché y evitan acceden directamente la disco o a la memoria RAM, y en un sistema suele haber más de un microprocesador con más de un "core" cada uno, y es frecuente que compartan los mismos datos, figúrate. Apropósito de esto, el C++ define su "memory model" https://en.cppreference.com/w/cpp/language/memory_model
[/Nota]
#70
Cita de: RayR en  2 Mayo 2019, 21:20 PM

No. Es tal cuál lo puse. Reitero, yo me estoy guiando en lo que digimikeh pidió, que es un tamaño de 10x10.

Ah, Ok, cierto.