4 General principles [intro]

4.6 Program execution [intro.execution]

Семантические описания в этом международном стандарте определяют параметризованную недетерминированную абстрактную машину. Этот международный стандарт не предъявляет требований к структуре соответствующих реализаций. В частности, им не нужно копировать или имитировать структуру абстрактной машины. Скорее, соответствующие реализации требуются для имитации (только) наблюдаемого поведения абстрактной машины, как объяснено ниже.6

Некоторые аспекты и операции абстрактной машины описаны в этом международном стандарте как определяемые реализацией (например, sizeof(int)). Они составляют параметры абстрактной машины. Каждая реализация должна включать документацию, описывающую ее характеристики и поведение в этих отношениях.7 Такая документация должна определять экземпляр абстрактной машины, который соответствует этой реализации (далее именуется «соответствующий экземпляр»).

Некоторые другие аспекты и операции абстрактной машины описаны в этом международном стандарте как неуказанные (например, оценка выражений в a, new-initializerесли функция распределения не может выделить память ([expr.new])). Там, где это возможно, в этом международном стандарте определяется набор допустимого поведения. Они определяют недетерминированные аспекты абстрактной машины. Таким образом, экземпляр абстрактной машины может иметь более одного возможного выполнения для данной программы и данного ввода.

Некоторые другие операции описаны в этом международном стандарте как неопределенные (например, эффект попытки изменитьconst объект). [ Note: Этот международный стандарт не предъявляет требований к поведению программ, которые содержат неопределенное поведение. ]end note

Соответствующая реализация, выполняющая правильно сформированную программу, должна производить такое же наблюдаемое поведение, как одно из возможных выполнений соответствующего экземпляра абстрактной машины с той же программой и теми же входными данными. Однако, если любое такое выполнение содержит неопределенную операцию, этот международный стандарт не налагает никаких требований на реализацию, выполняющую эту программу с этим вводом (даже в отношении операций, предшествующих первой неопределенной операции).

Экземпляр каждого объектаautomatic storage duration связан с каждой записью в его блоке. Такой объект существует и сохраняет свое последнее сохраненное значение во время выполнения блока и пока блок приостановлен (посредством вызова функции или получения сигнала).

Наименьшие требования к соответствующей реализации:

  • Доступ через изменчивые значения gl оценивается строго в соответствии с правилами абстрактной машины.

  • При завершении программы все данные, записанные в файлы, должны быть идентичны одному из возможных результатов, которые могло бы дать выполнение программы в соответствии с абстрактной семантикой.

  • Динамика ввода и вывода интерактивных устройств должна происходить таким образом, чтобы вывод подсказки фактически доставлялся до того, как программа ожидает ввода. Что представляет собой интерактивное устройство, определяется реализацией.

Все вместе они называются observable behavior программой. [ Note: Более строгое соответствие между абстрактной и фактической семантикой может быть определено каждой реализацией. ]end note

[ Note: Операторы могут быть перегруппированы в соответствии с обычными математическими правилами только в том случае, если операторы действительно ассоциативны или коммутативны.8 Например, в следующем фрагменте

int a, b;
/* ... */
a = a + 32760 + b + 5;

оператор выражения ведет себя точно так же, как

a = (((a + 32760) + b) + 5);

из-за ассоциативности и приоритета этих операторов. Таким образом, результат суммы(a + 32760) затем добавляется кb, и этот результат затем добавляется к 5, что дает значение, присвоенное a. На машине, в которой переполнение вызывает исключение и в котором диапазон значений, представленных какint есть [-32768, +32767], реализация не может переписать это выражение как

a = ((a + b) + 32765);

поскольку, если бы значения дляa иb были соответственно -32754 и -15, сумма выдалаa + b бы исключение, а исходное выражение - нет; также нельзя переписать это выражение как

a = ((a + 32765) + b);

или

a = (a + (b + 32765));

поскольку значения дляa иb могли быть, соответственно, 4 и -8 или -17 и 12. Однако на машине, на которой переполнение не вызывает исключения и в котором результаты переполнения обратимы, приведенный выше оператор выражения может быть переписан реализацией любым из вышеперечисленных способов, потому что будет получен тот же результат. ]end note

Aconstituent expression определяется следующим образом:

  • Составным выражением выражения является это выражение.

  • Составные выражения a braced-init-listили a (возможно, заключенные в скобки) expression-list являются составными выражениями элементов соответствующего списка.

  • Составные выражения brace-or-equal-initializer вида являются составными выражениями . = initializer-clauseinitializer-clause

[Example:

struct A { int x; };
struct B { int y; struct A a; };
B b = { 5, { 1+1 } };

Составляющие выражения, initializer используемые для инициализации, -b это5 и1+1. ]end example

immediate subexpressions Выраженияe являются

  • составные выраженияeоперандов (пункт[expr]),

  • любой вызов функции, которыйe неявно вызывает,

  • еслиe является a lambda-expression, инициализация сущностей, захваченных копией, и составляющих выражений initializerобъекта init-captures,

  • ife являетсяfunction call или неявно вызывает функцию, составляющие выражения каждого из них,default argument используемые в вызове, или

  • еслиe создаетaggregate объект, составляющие выражения каждого элемента по умолчанию initializer ([class.mem]), используемые при инициализации.

Asubexpression выраженияe - это непосредственное подвыражениеe или подвыражение непосредственного подвыраженияe. [ Note: Выражения, встречающиеся в compound-statementa lambda-expression , не являются частями выражения lambda-expression. ]end note

Аfull-expression это

Если языковая конструкция определена для неявного вызова функции, использование языковой конструкции считается выражением для целей этого определения. Преобразования, применяемые к результату выражения для удовлетворения требований языковой конструкции, в которой появляется выражение, также считаются частью полного выражения. Для инициализатора выполнение инициализации объекта (включая оценку инициализаторов членов по умолчанию для агрегата) также считается частью полного выражения. [Example:

struct S {
  S(int i): I(i) { }       // full-expression is initialization of I
  int& v() { return I; }
  ~S() noexcept(false) { }
private:
  int I;
};

S s1(1);                   // full-expression is call of S​::​S(int)
void f() {
  S s2 = 2;                // full-expression is call of S​::​S(int)
  if (S(3).v())            // full-expression includes lvalue-to-rvalue and
                           // int to bool conversions, performed before
                           // temporary is deleted at end of full-expression
  { }
  bool b = noexcept(S());  // exception specification of destructor of S
                           // considered for noexcept
  // full-expression is destruction of s2 at end of block
}
struct B {
      B(S = S(0));
   };
   B b[2] = { B(), B() };  // full-expression is the entire initialization
                           // including the destruction of temporaries

end example]

[ Note: Оценка полного выражения может включать оценку подвыражений, которые лексически не являются частью полного выражения. Например, подвыражения, участвующие в оценке default arguments , считаются созданными в выражении, вызывающем функцию, а не в выражении, определяющем аргумент по умолчанию. ]end note

Чтение объекта, обозначенного avolatile glvalue, изменение объекта, вызов функции ввода-вывода библиотеки или вызов функции, которая выполняет любую из этих операций, - все side effectsэто изменения в состоянии среды выполнения.Evaluation выражения (или подвыражения) в целом включает в себя как вычисления значений (включая определение идентичности объекта для оценки glvalue и выборку значения, ранее присвоенного объекту для оценки prvalue), так и инициирование побочных эффектов. Когда вызов функции ввода-вывода библиотеки возвращается или оценивается доступ через изменчивое значение glvalue, побочный эффект считается завершенным, даже если некоторые внешние действия, подразумеваемые вызовом (например, сам ввод-вывод) илиvolatile доступом, могут еще не завершены.

Sequenced before представляет собой асимметричное, транзитивное, попарное отношение между оценками, выполняемыми однимthread, что приводит к частичному порядку среди этих оценок. Для любых двух вычисленийA и B, еслиA выполняется последовательность доB (или, что то же самое,B естьsequenced afterA), то выполнение A должно предшествовать выполнениюB. ЕслиA последовательность не была установлена ​​раньшеB иB не была установлена ​​предыдущаяA, тоA и B являютсяunsequenced. [ Note: Выполнение неупорядоченных оценок может перекрываться. ] Оценки и относятся к случаям , когда последовательность либо предшествует, либо предшествует , но не указано, какая именно. [ Неопределенно последовательные оценки не могут перекрываться, но любая из них может быть выполнена первой. ] Выражение считается упорядоченным перед выражением, если каждое вычисление значения и каждый побочный эффект, связанный с выражением , упорядочен перед каждым вычислением значения и каждым побочным эффектом, связанным с выражением .end noteA B indeterminately sequenced A B B ANote: end noteXY XY

Каждое вычисление значения и побочный эффект, связанный с полным выражением, упорядочивается перед каждым вычислением значения и побочным эффектом, связанным со следующим оцениваемым полным выражением.9

Если не указано иное, вычисления операндов отдельных операторов и подвыражений отдельных выражений неупорядочены. [ Note: В выражении, которое оценивается более одного раза во время выполнения программы, неупорядоченные и неопределенно упорядоченные вычисления его подвыражений не обязательно должны выполняться последовательно в разных вычислениях. ] Вычисления значений операндов оператора последовательно выполняются перед вычислением значения результата оператора. Если побочный эффект в a не упорядочен относительно другого побочного эффекта в той же ячейке памяти или вычисления значения с использованием значения любого объекта в той же ячейке памяти, а это не так , поведение не определено. [ В следующем разделе налагаются аналогичные, но более сложные ограничения на потенциально параллельные вычисления. ]end notememory location potentially concurrentNote: end note

[Example:

void g(int i) {
  i = 7, i++, i++;    // i becomes 9

  i = i++ + 1;        // the value of i is incremented
  i = i++ + i;        // the behavior is undefined
  i = i + 1;          // the value of i is incremented
}

end example]

При вызове функции (независимо от того, является ли функция встроенной), каждое вычисление значения и побочный эффект, связанный с любым выражением аргумента или с постфиксным выражением, обозначающим вызываемую функцию, упорядочиваются перед выполнением каждого выражения или оператора в теле вызываемая функция. Для каждого вызова функцииF, для каждой оценки,A которая происходит внутри,F и каждой оценкиB , которая не происходит внутри,F но оценивается в том же потоке и как часть одного и того же обработчика сигнала (если есть), либоA упорядочивается до,B либо B упорядочивается раньшеA.10 [ Note: ЕслиA иB не были бы иначе упорядочены, то они неопределенно упорядочены. ] Некоторые контексты в C ++ вызывают оценку вызова функции, даже если соответствующий синтаксис вызова функции отсутствует в единице перевода. [ Оценка вызывает одну или несколько функций выделения и конструктора; см . В другом примере вызов a может возникать в контекстах, в которых не появляется синтаксис вызова функции. ] Ограничения последовательности выполнения вызываемой функции (как описано выше) являются особенностями вызовов функций в том виде, в каком они оцениваются, независимо от синтаксиса выражения, вызывающего функцию. end noteExample: new-expression[expr.new]conversion function end example

Если обработчик сигнала выполняется в результате вызоваstd​::​raise функции, то выполнение обработчика упорядочивается после вызоваstd​::​raise функции и до ее возврата. [ Note: Когда сигнал получен по другой причине, выполнение обработчика сигнала обычно не упорядочено по отношению к остальной части программы. ] end note

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

Эта документация также включает условно поддерживаемые конструкции и поведение, зависящее от локали. Смотрите[intro.compliance].

Перегруженные операторы никогда не считаются ассоциативными или коммутативными.

Как указано в[class.temporary], после оценки полного выражения имеет место последовательность из нуля или более вызовов функций деструктора для временных объектов, обычно в обратном порядке построения каждого временного объекта.

Другими словами, выполнение функций не чередуется друг с другом.