Re[2]: Безопасно ли присваивать один указатель другому?..
От: okman Беларусь https://searchinform.ru/
Дата: 23.03.18 06:10
Оценка: 47 (6)
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, okman, Вы писали:


O>>Или такое присваивание всегда безопасно, даже если сами указатели содержат null или "мусор"?


AG>Я бы не стал присваивать неинициализированный мусор, потому что инструменты статического анализа кода имеют право дважды ругнуться.

AG>Во-первых, мы используем значение неинициализированной переменной.
AG>Во-вторых, мы же потом не разыменовываем целевой указатель, так? Вот и неиспользованное присвоенное значение.

AG>Что до легальности с точки зрения С/С++.

AG>Есть такая штука, как signaling NaN.
AG>Она может привести к тому, что следующее присвоение упадёт:
AG>
AG>float f1;
AG>float f2;
AG>f2 = f1;
AG>

AG>Если под это есть "законодательная база" в С/С++, то, возможно, она применима и к указателям.

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

#include <cstdio>

struct Base
{
    virtual ~Base() {}
};

struct X1 : public virtual Base {};
struct X2 : public virtual Base {};
struct Child : public X1, public X2 {};

int main()
{
    X1 * p1 = new X1();
    delete p1;
    Base * p2;
    p2 = p1;
    printf("p2 = %p\r\n", (void *)p2);
    return 0;
}

При запуске на VS2015 или VS2008 в режиме Debug программа падает на строке 'p2 = p1':

"Exception thrown at [...] in MyProgram.exe: 0xC0000005: Access violation reading location [...]".

Аналогично ведут себя онлайн-компиляторы:

codepad (C++) — Segmentation fault
http://codepad.org/ZdbdFm98

ideone (C++14) — Runtime error
https://ideone.com/HRCX3A

rextester (C++ gcc) — Invalid memory reference (SIGSEGV)
http://rextester.com/XKG97608

rextester (C++ clang) — Invalid memory reference (SIGSEGV)
http://rextester.com/GAKSE23949

Ключевой момент — виртуальное наследование X1 и X2 от Base.

Хотелось бы понять, насколько такое поведение (т.е. разыменование указателя, возможно висячего,
при выполнении приведений типов по иерархии наследования) легально с точки зрения стандарта C++.
Или же это сугубо implementation-defined?..
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.