Страницы

Поиск по вопросам

понедельник, 3 февраля 2020 г.

Умные указатели (unique_ptr) и вызов функций-членов класса

#cpp #указатели


Собственно, ковыряю то, что написано в теме вопроса. Проблема возникла, когда я намеренно
написал косячный код, а он, блин не упал.

Собственно, код:

#include 
#include 

struct cdmem {
    cdmem()             { std::cout << this << " :: cdmem::cdmem()"             <<
std::endl; };
    cdmem(const cdmem&) { std::cout << this << " :: cdmem::cdmem(const cdmem&)" <<
std::endl; };
    cdmem(const cdmem*) { std::cout << this << " :: cdmem::cdmem(const cdmem*)" <<
std::endl; };

    void testf()        { std::cout << this << " :: testf()"                    <<
std::endl; };

    ~cdmem()            { std::cout << this << " :: cdmem::~cdmem()"            <<
std::endl; };
};


int main() {
    std::unique_ptr pd(new cdmem);
    if(!pd) {
        std::cout << "\n ERR1 " << std::endl;
        return 1;
    }
    pd->testf();
    auto pd1(std::move(pd));
    pd->testf(); // Вот тут указатель уже нулевой
    return 0;
}


Вывод:

0x801c06058 :: cdmem::cdmem()
0x801c06058 :: testf()
0x0 :: testf() // this равен 0x0
0x801c06058 :: cdmem::~cdmem()


Получается, что обращения к самому объекту не происходит?
    


Ответы

Ответ 1



Это классическое UB, (обращение к более невалидному указателю), которое в данном случае выражается в нормальной работе. Это частный случай, который в другой ситуации (навскидку - виртуальный метод и вырубленная оптимизация) выстрелит вам в ногу. Не делайте так.

Ответ 2



Тут играет роль неопределённое поведение. #include struct A { void foo() { std::cout << "A::foo()\n"; } }; int main() { A * a = nullptr; a->foo(); } Вывод: A::foo() Это работает в MinGW 5.1.0, но далеко не факт что это будет работать в других версиях и в других компиляторах.

Ответ 3



Классический случай UB. Если хотите чтобы 100% программа упала, попробуйте добавить в исследуемую структуру любое поле с данными (например int field = 12;) и обратиться к нему в вызываемой функции.

Ответ 4



Вызов невиртуальной функции компилируется в обычный вызов функции с передачей параметром указателя this, в данном случае NULL. Если вы хотите настоящий UB - вызывайте виртуальную функцию.

Комментариев нет:

Отправить комментарий