2015-06-07 3 views
2

Я опущу заголовкиКак определить порядок вызова функций C++?

class X { 
    int i; 
    static int j; 

public: 
    X(int ii = 1) : i(ii) { 
     j = i; 
    } 
    static int incr() { 
     return ++j; 
    } 
    static int f() { 
     return incr(); 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) { 
    X x; 
    X* xp = &x; 
    cout << x.f() << xp->f() << X::f(); 

    return 1; 
} 

Эта последовательность печатает 432, но на первый взгляд можно подумать, что будет печатать 234.

Как мог точный порядок вызовов функций определяется? Что мне не хватает?

+0

Порядок оценки параметров функции не задан, см. здесь [здесь] (http://herbsutter.com/gotw/_102/) – davidhigh

+0

У вас нет промежуточной точки последовательности между различными модификациями в 'j', поэтому порядок неопределен. –

ответ

2

§ 1.9.13

секвенированы перед тем является асимметричным, транзитивным, попарно соотношение между оценками, выполненных одной нитью (1.10), которое индуцирует частичный порядок среди этих оценок. При любых двух оценках A и B, если A секвенирован до B, то выполнение A должно предшествовать исполнению B. Если A не секвенировано до B и B не секвенированы до A, тогда A и B не подвержены , [Примечание. Выполнение необоснованных оценок может перекрываться. -end note] Оценки A и B неопределенно секвенированы, когда либо A секвенирован до того, как B или B секвенированы до A, но не определено, что. [Примечание. Неопределенно оценки секвенирования не могут перекрываться, но либо могут быть выполнены в первую очередь. -end note]

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

Рассмотрим следующий пример:

int a[3]; 

void f1() { a[0] = 1; } 
void f2() { a[1] = 2; } 
void f3() { a[2] = 3; } 

int main() { 
    f1(), f2(), f3(); 
} 

В принципе язык не утверждает никаких требований при заказе на заявлении, как

std::cout << f1() << f2() << f3(); 

Ваш код не имеет точек последовательности (http://en.wikipedia.org/wiki/Sequence_point) между вызовами функции; вы можете определить порядок, который генерирует ваш компилятор, но он может вести себя по-разному на другом процессоре или на другом уровне оптимизации.

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

std::cout << f1(); 
std::cout << f2(); 
std::cout << f3(); 

или

auto a1 = f1(); 
auto a2 = f2(); 
auto a3 = f3(); 
std::cout << a1 << a2 << a3; 
+0

@DavidHaim Спасибо :) – kfsone

2

Оператор потока - просто оператор. C++ allows operators to be defined a multitude of ways. Что вы видите, это оператор < < для строк. То, что вы делаете то же самое, как:

cout << "word1" << "word2" << "word3"; 

ожидать выход для этого есть:

"word1word2word3" 

Однако порядок оценки определяется реализацией оператора < <. Обычно выше эквивалентно:

(((cout << "word1") << "word2") << "word3"); 

Заменить строки с функциями вместо и вы видите первый один оценивается на самом деле «word3». Это не совсем так, просто то, что вы обычно увидите.

(((cout << func1()) << func2()) << func3()); 

порядок оценки будет FUNC3, func2, func1, при заказе печати возвращение func1, func2, FUNC3.

+0

Порядок оценки не определяется реализацией оператора '<<'. Он определяется компилятором. Оператор, как и любая функция, не имеет контроля над порядком, в котором оцениваются его аргументы. –

1

Это утверждение

cout << x.f() << xp->f() << X::f(); 

может быть переписанный как

cout.operator <<(x.f()).operator <<(xp->f()).operator <<(X::f()); 

Порядок оценок выражений, используемых в качестве аргументов в этом утверждении, не указан. Поэтому компилятор может оценивать их, например, слева направо или справа налево. Таким образом, используя различные компиляторы вы можете получить разные результаты. :)

Чтобы получить детерминированный результат вы должны переписать заявление

cout << x.f() << xp->f() << X::f(); 

, например, как

cout << x.f(); 
cout << xp->f(); 
coit << X::f(); 
Смежные вопросы