Как думаете, возможно ли в C или C++ получить какой-нибудь побочный эффект во время
присваивания одного указателя другому? Т.е., упрощенно говоря, может ли программа упасть
на выполнении простой конструкции типа x = y? Считаем, что x и y — это самые обычные
"сырые" указатели, т.е. не смарт-поинтеры, не классы с переопределенным оператором
присваивания и ничего такого, а просто самые обычные указатели:
SomeType * x;
AnotherType * y;
//
// здесь много разного кода.
// x и y присваиваются всякие значения,
// а может и не присваиваются...
//
x = y;
Или такое присваивание всегда безопасно, даже если сами указатели содержат null или "мусор"?
Re: Безопасно ли присваивать один указатель другому?..
Здравствуйте, okman, Вы писали:
O>Как думаете, возможно ли в C или C++ получить какой-нибудь побочный эффект во время O>присваивания одного указателя другому?
Гонки?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[2]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, okman, Вы писали:
O>Считаем, что x и y — это самые обычные O>"сырые" указатели, т.е. не смарт-поинтеры, не классы с переопределенным оператором O>присваивания и ничего такого, а просто самые обычные указатели:
O>
O>SomeType * x;
O>AnotherType * y;
O>
O>Или такое присваивание всегда безопасно, даже если сами указатели содержат null или "мусор"?
если "не смарт-поинтеры, не классы с переопределенным оператором присваивания", то можно говорить о
char* x;
char* y;
?
Тогда точно безопасно.
Иначе — в чём разница?
Re[2]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, okman, Вы писали:
O>Как думаете, возможно ли в C или C++ получить какой-нибудь побочный эффект во время O>присваивания одного указателя другому? Т.е., упрощенно говоря, может ли программа упасть O>на выполнении простой конструкции типа x = y? Считаем, что x и y — это самые обычные O>"сырые" указатели, т.е. не смарт-поинтеры, не классы с переопределенным оператором O>присваивания и ничего такого, а просто самые обычные указатели:
Переопределение оператора присваивания — здесь НЕ в тему (присваиваются всё-таки указатели, а не сами объекты) — так что этого бояться не нужно.
O>
O>SomeType * x;
O>AnotherType * y;
O>//
O>// здесь много разного кода.
O>// x и y присваиваются всякие значения,
O>// а может и не присваиваются...
O>//
O>x = y;
O>
O>Или такое присваивание всегда безопасно, даже если сами указатели содержат null или "мусор"?
Здесь главный вопрос:
Как связаны между собой SomeType и AnotherType???
Если это совершенно разные типы (никак не связянные наследованием) — то это ИМХО не безопасно
В общем, я бы сделал так:
if (dynamic_cast<SomeType*>(y))
{
x = y;
}
Вся проблема в том, что если SomeType и AnotherType никак не связаны между собой по иерархии классов, то само по себе присвоение указателя конечно же пройдет, но он будет указывать на объект СОВСЕМ другого типа (при дальнейшей работе с указателем "x" добро пожаловать в мир UB)...
Здравствуйте, okman, Вы писали:
O>Как думаете, возможно ли в C или C++ получить какой-нибудь побочный эффект во время присваивания одного указателя другому?
Если сильно надо, то можно
struct A {
int *x, *y;
void fn() {
x=y;
}
};
int main(int argc,char** argv) {
A *a=0;
a->fn();
return 0;
}
А вообще дурдом с этими UB. Скоро неправильное количество пробелов будет UB.
При этом компилятор в случае UB молча будет пытаться сгенерировать максимально неожиданный код.
Re: Безопасно ли присваивать один указатель другому?..
Здравствуйте, okman, Вы писали:
O>Или такое присваивание всегда безопасно, даже если сами указатели содержат null или "мусор"?
Я бы не стал присваивать неинициализированный мусор, потому что инструменты статического анализа кода имеют право дважды ругнуться.
Во-первых, мы используем значение неинициализированной переменной.
Во-вторых, мы же потом не разыменовываем целевой указатель, так? Вот и неиспользованное присвоенное значение.
Что до легальности с точки зрения С/С++.
Есть такая штука, как signaling NaN.
Она может привести к тому, что следующее присвоение упадёт:
float f1;
float f2;
f2 = f1;
Если под это есть "законодательная база" в С/С++, то, возможно, она применима и к указателям.
O>x = y;
Гипотетически, указатель может представлять собой пару селектор:адрес. И опять же, гипотетически, y может быть переменной гдето в памяти, а x — компилятор решит разместить в регистрах "прямо ща". И далее читаем тут:
If the destination operand is a segment register (DS, ES, FS, GS, or SS), the source operand must be a valid segment selector. In protected mode, moving a segment selector into a segment register automatically causes the segment descriptor information associated with that segment selector to be loaded into the hidden (shadow) part of the segment register. While loading this information, the segment selector and segment descriptor information is validated (see the "Operation" algorithm below).
..то есть, присвоение сегментому регистру значения невалидного селектора (в защищенном режиме сегментные регистры содержат селекторы) вызывает падение.
Но поскольку чуть более чем почти все оси, работающие в защищенном режиме, предоставляют процессу одно плоское адресное пространство, то хранить значение селектора в переменной-указателе смысла нету, потому присвоение указателя не хряпнется.
Но в принципе могут быть более другие архитектуры, у которых например все обращения к памяти могут делаться только через какой нить спец. регистр — указатель, и который к примеру может принимать только выровненное на размер слвоа значение, а попытка присвоения такому регистру невыровненного значения вызовет ошибку защиты.
Как много веселых ребят, и все делают велосипед...
O>SomeType * x;
O>AnotherType * y;
O>//
O>// здесь много разного кода.
O>// x и y присваиваются всякие значения,
O>// а может и не присваиваются...
O>//
O>x = y;
O>
O>Или такое присваивание всегда безопасно, даже если сами указатели содержат null или "мусор"?
почему-то никто не отметил самого очевидного -- попытки дереференсить любой из указателей это нарушение strict aliasing, т.е. в конечом итоге UB (если не заморачиваться отдельно).
Re[2]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, 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 [...]".
Ключевой момент — виртуальное наследование X1 и X2 от Base.
Хотелось бы понять, насколько такое поведение (т.е. разыменование указателя, возможно висячего,
при выполнении приведений типов по иерархии наследования) легально с точки зрения стандарта C++.
Или же это сугубо implementation-defined?..
Re[3]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, okman, Вы писали:
O>Хотелось бы понять, насколько такое поведение (т.е. разыменование указателя, возможно висячего, O>при выполнении приведений типов по иерархии наследования) легально с точки зрения стандарта C++. O>Или же это сугубо implementation-defined?..
ссылок на стандарт не приведу, но чисто логически падение оправдано, т.к. идет обращение по невалидному адресу, который уже может быть возвращен ОС.
Re[3]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, okman, Вы писали:
O>struct X1 : public virtual Base {}; O>struct X2 : public virtual Base {}; O>struct Child : public X1, public X2 {};
O>int main() O>{ O> X1 * p1 = new X1(); O> delete p1; O> Base * p2; O> p2 = p1; O> printf("p2 = %p\r\n", (void *)p2); O> return 0; O>} O>[/cpp]
O>Ключевой момент — виртуальное наследование X1 и X2 от Base.
Вот поэтому и пишут в книге "C++ для чайников":
Всегда инициализируйте указатели в конструкторах и всегда обнуляйте указатель после освобождения памяти, на которую он указывает. Эти действия лишними не бывают.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, zaufi, Вы писали:
Z>почему-то никто не отметил самого очевидного -- попытки дереференсить любой из указателей это нарушение strict aliasing, т.е. в конечом итоге UB (если не заморачиваться отдельно).
А де там dereference? Мы ж только присвоили.
Русский военный корабль идёт ко дну!
Re: Безопасно ли присваивать один указатель другому?..
Здравствуйте, okman, Вы писали:
O>Привет!
O>Как думаете, возможно ли в C или C++ получить какой-нибудь побочный эффект во время O>присваивания одного указателя другому? Т.е., упрощенно говоря, может ли программа упасть O>на выполнении простой конструкции типа x = y? Считаем, что x и y — это самые обычные O>"сырые" указатели, т.е. не смарт-поинтеры, не классы с переопределенным оператором O>присваивания и ничего такого, а просто самые обычные указатели:
O>
O>SomeType * x;
O>AnotherType * y;
O>//
O>// здесь много разного кода.
O>// x и y присваиваются всякие значения,
O>// а может и не присваиваются...
O>//
O>x = y;
O>
O>Или такое присваивание всегда безопасно, даже если сами указатели содержат null или "мусор"?
А если это указатели на методы? Где-то слышал, что указатель на метод — это далеко не (void *). Если кто-то может — киньте ссылкой на внятное объяснение.
Re[3]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, zaufi, Вы писали:
Z>>почему-то никто не отметил самого очевидного -- попытки дереференсить любой из указателей это нарушение strict aliasing, т.е. в конечом итоге UB (если не заморачиваться отдельно).
AG>А де там dereference? Мы ж только присвоили.
ну в данном коде не видать конечно... но указатели ведь присваивают чтобы когда-нибудть дереференснуть %)
Re[2]: Безопасно ли присваивать один указатель другому?..
Здравствуйте, SaZ, Вы писали:
SaZ>А если это указатели на методы? Где-то слышал, что указатель на метод — это далеко не (void *). Если кто-то может — киньте ссылкой на внятное объяснение.
Скажем так: это далеко не (void *), а более сложный тип — вот как первый параметр в _beginthread: https://msdn.microsoft.com/en-us/library/kdzttdcb.aspx
Справедливости ради: первый параметр в _beginthread — указатель на глобальную функцию или на статический метод класса.