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

#21
El C++Builder y Delphi fueron comprados hace varios años por Embarcadero, y hace un par de días acaba de sacar la versión 10.4

La versión Community es gratuita para hobby o desarrolladores con ingresos menores a una suma que no me acuerdo, pero podrás googlearlo.

Si te interesara alguna opinión
1) El C++ no es para programas con ventanas (Stroustrup).
2) Serás el único que use C++Builder en miles de kilómetros a la redonda.
3) Si usas la licencia Community, ten en cuenta que dura un año, y nadie sabe si podrás renovarla el año próximo. La idea de esta versión es que sea previa a la compra, y si esa opción está entre tus planes, adelante; si no, piénsalo.
4) Si quieres resucitar alguna aplicación Windows 98, es una buena oportunidad.
#22
¿dijsktra?

¿Puede ser que estés haciendo tu tributo jugando con el nombre del homenajeado?

https://www.britannica.com/biography/Edsger-Dijkstra

#23
Puedes hacer algo como esto, pero ten en cuenta que en C++ no debes usar punteros, no debes usar new (ni delete).

#include <iostream> // para cout
#include <cstring>  // para strncpy

int NombreFuncion(char* Dato, size_t &BufferDato) {
const char* texto = "resultado";
if (BufferDato < strlen(texto)+1) {
BufferDato = strlen(texto) +1;
return 0; // texto es más largo que BufferDato
}
strncpy(Dato, texto, BufferDato);
Dato[BufferDato-1] = '\0';
return 1;
}

int main()
{
size_t size = 1;
char* dato = new char[size];

if (NombreFuncion(dato, size))
std::cout << "dato = " << dato << '\n';
else
std::cout << "dato debe ser al menos de " << size << " bytes\n";

delete[] dato;
}


#24
Puedes usar el programa "xwd" (https://www.x.org/releases/X11R7.5/doc/man/man1/xwd.1.html), invocado desde el tuyo con fork() y exec(), por ejemplo, o aprender cómo lo hace estudiando su código (https://github.com/johnlane/xorg-xwd), y quién sabe, quizá hasta puedas mejorarlo.
#25
Programación C/C++ / Re: Ayuda en threads
7 Noviembre 2019, 04:42 AM
Una forma puede ser usando una "signal" que le diga al thread cuando debe terminar, con pthread_kill() seguido de un pthread_join().

No es la respuesta completa pero puedes ver un ejemplo simple desde donde empezar en:

https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/ptkill.htm

#26
Programación C/C++ / Re: Punteros en estructuras
31 Octubre 2019, 22:20 PM
Cita de: Desiresportal en 31 Octubre 2019, 18:27 PM
Estoy desarrollando alguna cosilla y utilizo una estructura similar a la siguiente para almacenar y manejar datos en binario.

Código (cpp) [Seleccionar]

struct datos {
void *data;
unsigned int length;

datos();
void operator=(datos rDatos);
~datos();
}


Si tu struct datos es responsable del manejo de un recurso de tipo void*, probablemente necesites usar templates en su lugar, o tener muy en claro el significado y funcionamiento de las funciones especiales de una clase. Y me da la impresión de que no es el caso.

En el destructor pones
delete[] (unsigned char *)data;
de modo que estás forzando a que data sea de tipo unsigned char*, ya no void*, lo mismo cada vez que necesitas hacer ese cast.

Tu problema no está (solamente) en el operador de asignación, sino en la idea misma de manejar un recurso con una clase C++ y, si no te molesta un consejo de tipo general, necesitas un buen libro y estudiar seriamente, no es preguntando sobre errores al azar que se aprende un lenguaje de programación complejo; realmente, con este sistema te tomará años convertirte en un programador mediocre.
#27
Citar
Cita de: Loretz en Ayer a las 04:01
... usa la versión más eficiente sin preguntar. Sin trucos ++i hace menos cosas que i++.
CitarCon lo que está en negrita, quieres decir que tanto si se usa el postincremento como el preincremento, el compilador lo optimizará al mismo nivel? Es decir, que daría igual usar uno que otro? Lo digo porque yo era de los que empezó a programar y a hacer los for con i++ hasta que me dijeron que era mejor usar ++i, pero claro, eso me ha chocado con el tema de que el preincremento sí es mejor pero cuando se trata de objetos y no de tipos primitivos.

En general los compiladores reescriben tu código como les place, la única restricción es que se preserve el "observable behavior"; o sea: el compilador es libre de pasarse tu código por donde le plazca y poner en su lugar otra cosa, sólo está obligado a generar un ejecutable que haga lo mismo. Aprovechando que ya tuve la delicadeza de poder el link al docuemento del Estándar C++17, puedes consultar: parágrafo 4.6 Program execution - Nota 5.

De modo que aunque el compilador no esté obligado, casi seguro que lo hará, eso o algo diferente, a su criterio.

Con los tipos nativos no sólo es más fácil sino que además es muy difícil que notemos la diferencia, normalmente no suele haber un cuello de botella en i++ cuando i es un int. Ahora, si i es de tipo "Clase_con_copy_constructor_vicioso", la diferencia será notable, a no dudarlo.

Ah, ¿por qué la diferencia va a estar en el copy_constructor_vicioso? Por lo dicho, el postincremento devuelve una copia del objeto original sin incrementar.



#28
También:

Una función virtual pura convierte a la clase en una Clase Base Abstracta (una ABC - abstract base class), con la idea de separar la interfaz de la implementación.

Suponte que trabajas en una empresa que tiene toda una colección de clases a las que sus programadores deben obligatoriamente adscribir. Será una buena idea que se presenten como una "Interfaz" pura (una clase abstracta) y que si en algún momento se necesita modificar alguna parte de su implementación, ninguno de los quichicientos programas y progamitas que la usaron necesitarán ser recompilados.

Va un ejemplo de uso:
Código (cpp) [Seleccionar]
#include <iostream>
#include <string>

// Interfaz
class Empleado {
    //... todos lo que se pretende de un empleado abstracto
public:
    virtual std::string trabajar() = 0; // ya esto hace que la clase se abstracta.
    virtual void lamer_botas() {};
    virtual void ser_despedido() {};
    //...
};

// Un tipo de Empleado concreto:
//   - obligada a sobreescribir las funciones virtuales puras,
//   - se espera sobrescritas las otras virtuales
class Gerente : public Empleado {
    // ...
public:
    virtual std::string trabajar() override {
        return "Trabajen esclavos!\n";
    }

    // ...
};

void funcion_que_acepta_un_Empleado(Empleado& e) {
    std::cout << e.trabajar();
}

int main()
{
    //Empleado e; // Error: Empleado es una interfaz, no se puede crear un objeto de clase abstracta

    Gerente g; // Bien, este es un Empleado pero concreto.

    funcion_que_acepta_un_Empleado(g);  // esta funcion espera un Empleado como parametro.
}


Aquí la idea es que un Empleado es algo abstracto, una fantasía metafísica, inexistente en el mundo de las cosas. Pero se tienen funciones que trabajan con Empleados pasados por parámentro, de modo que se le puede pasar cualquier objeto que sea un Empleado concreto (de una clase derivada de Empleado). De este modo tienes código que actúa sobre Empleados, código genérico (durante la ejecución se decidirá de qué tipo de Empleado se trata).

Luego se podrá crear más tipos de Empleados, si hiciera falta, o modificar cualquiera de las funciones expuestas en la interfaz, y nadie sufrirá.


#29
Me meto en la conversación un poco tarde...

Yo creo estamos todos de acuerdo que es mala idea escribir
eros[j+1] = -numeros[j--];
Y se van dando distintas razones que vamos entendiendo, o más o menos. Lo bueno es que está claro que no se hace. La definición sólida de por qué no se hace está en "la documentación": Order of Evaluation (https://en.cppreference.com/w/cpp/language/eval_order)

Puse eso de "la documentación" entre comillas porque es lo más parecido que conozco a una documentación de consulta eficiente, y que para mí es suficiente. Para cosas más peludas siempre queda la documentación oficial, el documento del estándar C++17; lo que establece qué es C++ y qué no lo es. La ley: (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf)

En este caso, me parece que no es necesario ser tan drástico y que el artículo de "la documentación" es más que suficiente; sobre todo cuando dice que este tipo de expresiones se califican como UB, Undefined Behavior, que no quiere decir "comportamiento indefinido", o que algo no está del todo bien, es una categoría específica que invalida al programa enteramente; no es que alguna operación puede dar un resultado diferente a la misma operación en otros lenguajes, o que en un compilador pase una cosa y en otro otra; es bastante más drástico que eso: una UB convierte al programa en una pila de basura. Ver: [https://en.cppreference.com/w/cpp/language/ub]

Y con respecto al asunto este del pre-incremento o post-incremento, algunas veces dará lo mismo usar uno u otro y otras no, es porque hacen cosas diferentes. Por ejemplo:
    int i = 1;
    int j = ++i; // incrementa el valor de i y lo devueve.

    int k = i++; // incrementa el valor de i y devuelve 
                 // una copia de i antes de ser incrementado


En general los compiladores son más inteligentes y saben hacerlo mejor que yo, pero no pueden escapar a la realidad de que el post-incremento hace más cosas que el pre-incremento. En un ciclo for, donde se usa para incrementar la variable de control, el compilador puede lucirse con poco, usa la versión más eficiente sin preguntar. Sin trucos ++i hace menos cosas que i++.





#30
Los elementos del vector sí están ordenados (y no se repiten), sólo que son generados al azar. Pongo el algoritmo acá abajo:

Se invoca con el vector ya del tamaño apropiado; se carga con valores al azar, se ordena y se eliminan los duplicados:

Código (cpp) [Seleccionar]
void llenar(std::vector<int>& v, int min, int max)
{
    static std::random_device rd;
    static std::mt19937 mte(rd());
    std::uniform_int_distribution<int> dist(min, max);

    std::generate(v.begin(), v.end(), [&]() { return dist(mte); });

    std::sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
}
.