C ++: неразмещенный указатель на объект может быть повторно безопасно разыменован ... почему? - PullRequest
0 голосов
/ 09 апреля 2020

почему этот код работает практически надежно, не нестабилен, неопределен? это разыменование нераспределенных, висячих указателей на объекты. спасибо.

#include <iostream>
using namespace std;

class Base{
    public:
    void vf()
    {
        cout<<"vf\n";
    }
    void pr(){
        cout<<"vb\n";
    }
};

int main() {
    Base* b ;

    //Base * bp = new Base;   //trying to disrupt memory
    char ar[]= "ttttttttttt"; //trying to disrupt memory

    b->pr();
    char aa[]= "ttttttttttt";
    b->vf();
    return 0;
}

1 Ответ

3 голосов
/ 09 апреля 2020

Добро пожаловать в замечательный мир Неопределенное поведение ! Согласно C ++ spe c, поведение этой проблемы не определено, поэтому то, что вы видите, может работать в вашей системе, но может sh в других или наоборот.

Практически говоря, то, что здесь происходит, вероятно, является артефактом того, как компилятор генерирует код для функций-членов. Как правило, функция-член, которая выглядит следующим образом:

void doSomething() {
    cout << "Hello!" << endl;
}

, вероятно, будет скомпилирована, как если бы это была свободная функция, подобная этой:

void Base_doSomething(Base* this) {
    cout << "Hello!" << endl;
}

В этом смысле, когда вы пишете

bf->doSomething();

компилятор обрабатывает его так, как будто вы написали

Base_doSomething(bf);

, и ничего плохого не происходит, потому что Base_doSomething не ссылается на указатель this, где все случаются плохие вещи.

Так вот, это очень хрупко. Если вы попытаетесь прочитать какой-либо элемент данных типа Base, этот код обработает sh, потому что тогда вы читаете из неверного указателя. Точно так же, если бы doSomething была функцией virtual, вы получили бы cra sh, потому что для вызова виртуальной функции (обычно) требуется чтение из объекта-получателя, чтобы найти vtable , чтобы определить, какая функция вызвать, и висячий указатель приведет к плохому доступу к памяти.

Итак, подведем итог:

  • Этот код приводит к неопределенному поведению, поэтому конкретное поведение вы не гарантируется, что видение будет работать или работать на разных платформах.
  • Хотя синтаксически bp->doSomething() выглядит как разыменование указателя, на самом деле оно может не включать разыменование указателя.
  • Функции-члены обычно компилируются как свободные функции с указателем «неявный this», переданным в качестве первого аргумента.
  • Виртуальные функции работают не так, как это, поэтому вы ожидаете увидеть другое поведение там.

Надеюсь, это поможет!

...