LINUX.ORG.RU

Вопрос новичку на тему C++

 


0

6

Допустим, окончили вы мега-курсы, и приходите устраиваться C++-программистом. Написали «C++» в списке знаний и навыков в резюме, и с гордо поднятой головой шагаете на интервью.

И вот, вам дают такой вопросик. Скажите, что произойдёт при выполнении данного кода (код, разумеется, бредовый, иначе как проверить знание секретов C++?):

#include <iostream>

struct T
{
    int iVal = 0;
    void printValue() const
    {
        std::cout << "Value is " << iVal << std::endl;
    }
    void destruct()
    {
        delete this;
    }
};

int main()
{
    T x{9};
    x.destruct();
    x.iVal = 11;
    x.printValue();
}

Какой правильный ответ, и почему?

★★★★★

Последнее исправление: seiken (всего исправлений: 1)
Ответ на: комментарий от soomrack

Да уж, забавно. То есть формально не придраться, а по сути - фигня.

У меня в пет-проекте, Ада-подобном ЯП, прописаны чёткие правила вычисления достижимости кода. Как раз чтобы вот такие случаи не попадали под UB, а компилировали предсказуемый результат, либо сразу давали диагностику, если правила достижимости не соблюдены.

wandrien ★★
()
Ответ на: комментарий от Siborgium

Чтобы быть более конкретным:

#include <iostream>

int main() {
    std::cout << "Hello World!" << std::endl;
    while(1){};
    return 0;
}

void unreacheable() {
    std::cout << "Hello World!" << std::endl;
}

clang++ –Wall –O2 1.cxx

./a.out
Hello World!
Hello World!
Segmentation fault

clang version 15.0.7

А исход в коде выше вполне логичен. Бесконечный цикл – UB, поэтому выпиливается. ret в main не положили. Дальше управление переходит к следующей инструкции, которой оказывается unreachable.

Тут как раз есть некоторая разница в С и в С++, в плане UB для циклов while(1).

Т.е. это не зловредный компилятор, который тебе палки в колеса вставляет и вызывает непонятно что – просто так сложилось, что в main не оказалось ret, и управление провалилось дальше.

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

soomrack ★★★★★
()
Ответ на: комментарий от wandrien

Бесконечный цикл - это не UB.

Вот, вот.
А то какой то бред обсуждают, это всего лишь фича оптимизаций шланга.
Кто не согласен, с вас цитата из стандарта.

arax ★★
()
Последнее исправление: arax (всего исправлений: 1)
Ответ на: комментарий от wandrien

while(1) это вполне себе может быть UB, если внутри цикла кое-чего нет; а случаи что UB, а что не UB в С и С++ тут немного разные. Тут надо стандарт смотреть, я не помню точные формулировки. И при каком-то обновлении стандарта (давно) были длинные дискуссии почему нужно, почему плохо и что делать, соотв в С и С++ решили немного по-разному, ввиду разной сложившейся практики.

soomrack ★★★★★
()
Ответ на: комментарий от wandrien

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

прогу всегда можно завершить извне данного цикла, каким-нить сигналом, другим тредом и все такое. потому бесконечный цикл без слипа, это конечно не красиво, но нестрашно.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

прогу всегда можно завершить извне данного цикла, каким-нить сигналом, другим тредом и все такое. потому бесконечный цикл без слипа, это конечно не красиво, но нестрашно.

Про это дискуссии и были, т.к. while(1) может использоваться для ожидания сигнала извне и пр.

С т.з. стандарта:

C 2011 (6.8.5 Iteration Statements): в этом случае цикл должен выполняться, UB нет. Есть только замечание, что цикл с НЕ CONST условием можно выбросить если внутри него ничего не происходит (перечислено, что должно не происходить).

Не должно быть: no input, no output, does not access volatile objects, no synchronization or atomic operations in its body, controlling expression.

Тут вот может некоторое UB возникнуть при выкидывании этого цикла.

C++ 2017: нет никаких замечаний про выбрасывание цикла, просто цикл должен исполняться, пока условие не станет false.

soomrack ★★★★★
()
Последнее исправление: soomrack (всего исправлений: 2)
Ответ на: комментарий от eao197

Вроде бы в текущих версиях стандарта бесконечный цикл без сайд-эффектов все еще UB, поэтому есть предложение исправить это: http://wg21.link/P2809.

Так я про это и упомянул – UB может возникнуть, но только если условие не const, т.к. в этом случае иногда можно цикл выкинуть.

while(1){ что угодно } – тут все однозначно, никакого UB.

soomrack ★★★★★
()
Ответ на: комментарий от soomrack

Бред. Константность условия здесь ни при чем.

Если немного почитать документ по ссылке, то проблемой является отсутствие forward progress. Который в бесконечном цикле может выражаться только в виде сайдэффектов.

Т.е. даже если напихать сложных и долгих вычислений в цикл, если они не создают сайдэффектов в процессе – это UB. Или если условие не константное, но компилятор сможет доказать, что оно никогда не вычислится в false.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 2)
Ответ на: комментарий от Siborgium

Не понял.

Если условие константное, то стандарт прямо говорит, что нужно выполнять тело цикла пока условия не станет false. В этом нет никакого UB для выполнения while.

soomrack ★★★★★
()
Ответ на: комментарий от Siborgium

Т.е. даже если напихать сложных и долгих вычислений в цикл, если они не создают сайдэффектов в процессе – это UB.

«сайд эффекты» могут создавать сигналы, или другие треды. а если это крутится на barebone, то обработчики прерываний.

alysnix ★★★
()
Ответ на: комментарий от Siborgium

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

Далее если он может доказать, что условие false или вычислимо в false за конечное время, то он выбрасывает и остатки цикла целиком.

Вроде всё логично. Время выполнения кода само по себе не является разновидностью сайд-эффекта, поэтому конечный цикл без сайд эффектов эквивалентен отсутствию цикла.

Но если компилятор выбрасывает while (true) {}, это бага, так как любой код после такого цикла недостижим, а он становится достижимым.

wandrien ★★
()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от soomrack

Я объяснил:

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

wandrien ★★
()
Ответ на: комментарий от alysnix

Определение forward progress с точки зрения стандарта цитируется по ссылке на инициативу выше.

При этом нужно понимать, что все это буквоедство, и работает ровно настолько, насколько компилятор сможет проанализировать происходящее.

Siborgium ★★★★★
()
Ответ на: комментарий от soomrack

Если условие константное, то стандарт прямо говорит, что нужно выполнять тело цикла пока условия не станет false. В этом нет никакого UB для выполнения while.

Я устал. Почитайте хотя бы текст инициативы выше. Там в пункте «3. Standards» английским по белому цитируется стандарт, а именно

The implementation may assume that any thread will eventually do one of the following:

terminate,

make a call to a library I/O function,

perform an access through a volatile glvalue, or

perform a synchronization operation or an atomic operation.

ничего из этого поток исполнения, содержащий бесконечный цикл, не делает.

By omission, iteration statements are undefined if the controlling expression does not meet the criteria above.

Все.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Ну а говорю, что в стандарте прямо сказано, что terminate можно только если условие не const. А если условие const, то никаких тебе terminate, есть там сайд эффекты или нет их, выполняй тело цикла и все.

soomrack ★★★★★
()