Tengo este programa de prueba:

#include <iostream>
#include <memory>

class A {
public:
    A()
    {
        std::cout<<"A Constructor\n";
    }

    ~A(){
        std::cout<<"A Destructor\n";
    }

    void show()
    {
        std::cout<<"A::show()"<<'\n';
    }
};

int main()
{
    auto p1 = std::make_shared<A>();
    // Relinquishes ownership of p1 on the object
    // and pointer becomes NULL
    p1.reset();
    std::cout<<p1.get()<<'\n';
    std::cout<<p1.use_count()<<'\n';
    p1->show();
    return 0;
}

Lo que produce esta salida:

A Constructor
A Destructor
0
0
A::show()

Ejecuté esto a través de gdb y vi:

:
:
(gdb) s
A::show (this=0x0) at so.cpp:18
18              std::cout<<"A::show()"<<'\n';
(gdb) s
A::show()
:

La línea A::show (this=0x0) at so.cpp:18 indica que el recurso subyacente es nulo. Miré otra pregunta pero ahí estaba el puntero sin procesar utilizado para invocar la función miembro. ¿Es este caso demasiado similar al de esa pregunta, ya que p1->show() también debería ser equivalente a algo como p1.get()->show();? ¿Mi comprensión es correcta?

1
Zoso 16 oct. 2019 a las 14:20

1 respuesta

La mejor respuesta

Simplemente agregue un miembro de datos a la clase y podrá ver un comportamiento visualmente indefinido.

#include <iostream>
#include <memory>

class A {
public:
    A()
    {
        std::cout<<"A Constructor\n";
    }

    ~A(){
        std::cout<<"A Destructor\n";
    }

    void show()
    {
        std::cout<<"A::show()"<<'\n';
        ++x;
    }

    int x = 0;
};

int main()
{
    std::shared_ptr<A> p1(new A);
    // Relinquishes ownership of p1 on the object
    // and pointer becomes NULL
    p1.reset();
    std::cout<<p1.get()<<'\n';
    std::cout<<p1.use_count()<<'\n';
    p1->show();
    return 0;
}

Por ejemplo, en tiempo de ejecución, un error como este

Runtime error #stdin #stdout 0s 4280KB

Se puede mostrar.

Ese es el puntero nulo que se utilizó para acceder al miembro de datos.

0
Vlad from Moscow 16 oct. 2019 a las 11:25