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

#81
No tengo el valgrind y estoy con el Visual Studio, pero veo dos cosas:

1) [que no tiene nada que ver con tu pregunta, pero...] La función void print(ostream& s) no debería poder invocarse con un argumento temporal (un prvalue), como en
print(stringstream() << "Producer " << producer_id << " produced " << product << "\n");
Por alguna extraña razón tu compilador lo permite. Supongo que puedes sobrecargar la función print con una versión que acepte una rvalue reference:
Citarvoid print(ostream&& s) {
   cout << s.rdbuf() << flush;
   s.clear();
}


Y 2) en
Código (cpp) [Seleccionar]
is_not_full.wait(lock, [] { return products.size() != max_products; });
el predicado
Citarproducts.size() != max_products;
no garantiza que el lock no se levante debido a un wakeup espurio, haciendo que se intente ejecutar el push() por dos o más threads simultáneamente.

#82
Citar¿ Por qué se dice que la macro NULL no es recomendada en C++ ?

Acá va un ejemplo donde se invocan distintas funciones sobrecargadas:

#include <iostream>

void fun(int i)
{
    std::cout << "int 0\n";
}

void fun(int* p)
{
    std::cout << "puntero nulo\n";
}

int main()
{
    fun(0);       // no hay duda de cuál de las dos se invoca.
    fun(nullptr); // tampoco hay duda
    fun(NULL);    // ¿y ahora?
}



Además la constante nullptr (de tipo nullptr_t):

- Puede convertirse a cualquier tipo de puntero o puntero a miembro y a bool, pero a nada más.
- No puede ser usada en expresiones aritméticas.
- Puede comparase con el int 0 [[ como en if(p == 0) ]]
- Puede usarse en expresiones relacionales (expresiones que se evalúan a true o false) para compararse con punteros (u otro dato de tipo nullptr_t).

De todos modos, por una cuestión de compatibilidad, aún en C++17 es aceptable asignar 0 (o NULL) a un puntero, como en
char* pch = 0;
#83
Creo que no está del todo bien.

Pongo acá tu ejemplo añadiendo algunos textos que pueden ayudar:

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

void anular(int* v, int pos)
{
    std::cout << "la direccion de v es: " << &v << " pero apunta a " << v << " (igual que p)\n";
    v[pos] = 0;
}

int main()
{
    int* p; // sin inicializar. no es NULL
    // std::cout << p << '\n'; [[error -> no puede accederse a un puntero sin inicializar]]
    std::cout << "p es una variable que esta en algun lado, su direccion es: " << &p << '\n';

    p = nullptr; // se la asigna a p el valor cero (cero de puntero, nullptr no es la macro NULL, es de tipo nullptr_t).
    std::cout << "p apunta a: " << p << '\n';
   

    p = new int[2];
    std::cout << "Ahora p apunta a: " << p << '\n';
    std::cout << "pero su direccion sigue siendo: " << &p << '\n';

    p[0] = 1;
    p[1] = 2;

    anular(p, 1);

}


Yo lo diría así:
Un puntero es una variable como cualquier otra, en este caso, p es de tipo int*. Como toda variable está en algún lado, se puede tomar su dirección; además se le puede asignar un valor, otra dirección de memoria, aunque esa dirección de memoria que se asigna al puntero puede estar en el free store (memoria libre) o en la pila (stack), a p le da igual. Por ejemplo:int i=5; p = &i; // stack

En tu línea 6 tienes declarado el puntero p, pero sin inicializar, no apunta a NULL; probablemente apunte a algo pero no podemos saberlo, intentar acceder a qué apunta un puntero sin inicializar es un error que no debería siquiera compilar. Lo que sí puedes es leer su propia dirección, en dónde está. Entonces, en un puntero tenemos su propia dirección de memoria y la dirección de memoria a la que apunta.

Cuando pasas a p como parámetro de anular(), puedes ver que la dirección de v es diferente a la dirección de p, naturalmente, v está en el el stack frame de anular(), pero apunta a la misma dirección que apunta p. Puedes verlo ejecutando mi ejemplo.

Si observas los valores reales de las direcciones de memoria a donde apuntan p[0] y p[1] podrás ver que
1) p == &p[0];
2) &p[1] == &p[0] + sizeof(int*);

p y &p[0] podrían llegar a ser de tipos distintos, pero los dos guardan la misma dirección de memoria.

Como &p[0] y &p[1] son las direcciones consecutivas en memoria capaces de guardar sendos int(s), deben diferir en sizof(int*), ni más ni menos.
#84
Un poco tarde, pero ...
Aprovechando la curiosidad de que en el sistema ASCII las mayúsculas y minúsculas difieren en el sexto bit (difieren en 32, el carácter ' ' espacio), se puede hacer:

Código (cpp) [Seleccionar]
char* invertirFrase(char* frase) {

    char* i = frase;

    while( *frase ) {
        if(*frase != 32)
            *frase ^= 32;
        frase++;
    }
    return i;
}


Pero esto sólo vale para los caracteres ASCII desde la 'a' hasta la 'z' y desde la 'A' hasta la 'Z', peor no vale para las letras acentuadas o la eñe. Es sólo una curiosidad.

#85
En tu ejemplo, MostrarAtrb(vehiculo); recibe un objeto Vehicle, que no tiene ruedas ni cambios.

El tipo estático de tu objeto "vehiculo" (definido en tiempo de compilación) es Vehicle, y el tipo dinámico (definido durante la ejecución) también lo es. Y al hacer vehiculo = Automovil(); o vehiculo = Bicicleta(); se asigna a vehiculo sólo la parte común entre un tipo y el otro. Es lo que se llama "Objet slicing".

El dynamic_cast va a fallar siempre.

#86
Es lo que suele llamarse un "Elaborated Type Specifiers".

Se usa, por ejemplo, aunque no parece que fuera tu caso, cuando una variable tiene el mismo nombre que un tipo; por ejemplo:

Código (cpp) [Seleccionar]
class A {
public:
    int i;
};

class Actor {
public:
    class A objetoA;     //Que pinta class aqui?
    int A;               // que buena idea ponerle A!
};

int main()
{
    Actor a;
    a.objetoA.i = 5;
    a.A = 3;
}


También se puede usarse para impresionar a los amigos, acompañado de la frase "así es más expresivo, ¿verdad?"

#87
Lo que creo que está errada es la afirmación valorativa (eso de ser "adecuada a una estructura deque") aplicada a una hipotética implementación común de la std::deque en los compiladores de C++.

No sé si el libro de Nyhoff es buena fuente, de lo que estoy seguro es que tu pregunta contiene preconceptos que no pueden darse por válidos.

Por ejemplo, la idea de Deque (double-ended queue) es que se trata de una lista lineal donde las inserciones y eliminaciones (y en general cualquier tipo de acceso) se hacen en los extremos.

No creo que haya que decir mucho más que eso para saber que estamos hablando de una Deque y no de otra cosa. Es una idea general.


Por otro lado, la std::deque es un "sequence container" definido por el estándar C++. Y cada compilador implementa su propia versión de la std::deque de acuerdo con los requerimientos del estándar.

Ahora, ¿cómo puede decirse que una cierta implementación de std::deque es o no "del todo adecuada a una estructura Deque" ?

Mira, a riesgo de pasarme de pelma: Todos tenemos más o menos una idea común sobre qué es un Plumero. Pero decir que la Norma Industrial del Canadá no define adecuadamente las especificaciones de los plumeros porque la fábrica Plumita los elabora con un palo más corto de lo que me gustaría, es llevar las cosas demasiado lejos.

#88
El lenguaje especifica los "requerimientos" de cada uno; interfaces y grados de complejidad de las operaciones; no mucho más. Después cada compilador lo implementa como más le gusta.

CitarComo esta implementado el contenedor deque en c++,mencionando que realmente no seria una implementación del todo adecuada a un estructura 'deque' debido a que en el fondo contiene un vector map que permite la interfaz de una pila doble.

No sé qué libro estás leyendo, pero esa es una afirmación equivocada. Se debe estar refiriendo a alguna estructura conceptual más o menos común, pero si es o no "adecuada" depende solamente de si cumple o no con los requerimientos del estándar, interfaz y grados de complejidad.

#89
Para seguir con el ejemplo de la oficina...

El puntero global es como si guardara una copia de la llave, una copia de la variable local a.

Pero al dejar la oficina, el nuevo inquilino puede
- Cambiar la cerradura; en ese caso ptr ya no sirve.
- Dejar la cerradura como estaba, pero como se dedica a experimentos de transmutación genética, en el cajón donde tú creías que habías dejado la botella, ahora hay... ahora hay.... (NOOOOOOOOO)
#90
CitarEl espacio de memoria donde estaba contenido y que ahora es apuntado por el puntero ¿sigue estando reservado?
No, al volver de h() ya no está reservado.

Citares decir, ¿ese espacio de memoria sigue siendo considerado como ocupado por una variable?
No, ya no.

Citaro fue liberado al mismo tiempo que termino el tiempo de vida de la variable 'a'.
Sí, así es.

CitarTengo la incertidumbre de si ese pedazo de memoria regreso al conjunto de la memoria disponible...
Sí, vuelve a estar disponible (es una porción de memoria en la stack, automática).

Citar
... pero sin embargo sigue teniendo los valores que anteriormente fueron utilizados para representar a la variable 'a' ...
Puede tenerlos o no, después de volver de h() su valor es "indefinido" (quizá sí, quizá no), algunos compiladores le asignarán un cero, otros lo dejarán como está, en otros contendrá cualquier cosa al azar; para el lenguaje su valor es "indefinido".

Citar... y que pueda ser posible que por ahora el apuntador me siga mostrando ese valor pero sin embargo conforme vaya avanzando un programa y se reserve memoria etc...
Puede ser posible, pero depende del compilador y de la suerte que tengas ese día. Es lo que el estándar C++ califica como "Undefined Behavior" (comportamiento indefinido, si pretender leerlo o desreferenciarlo puede pasar cualquier cosa, normalmente mala).

CitarEse segmento de memoria pueda llegar a ser sobrescrito por un nuevo valor de una variable .
Sí, es memoria disponible para el programa, ¿por qué no?