2013-09-16 3 views
2

Рассмотрим следующий (немного задуманную) пример:Маркировка функции, как не имеющие каких-либо побочных эффектов, с помощью Visual C++

// a.cpp 
int mystrlen(const char* a) { 
    int l = 0; 
    while (a[l]) ++l; 
    return l; 
} 

// b.cpp 
extern int mystrlen(const char*); 
int foo(const char* text) { 
    return mystrlen(text) + mystrlen(text); 
} 

Было бы очень хорошо, чтобы быть в состоянии сказать компилятору, что mystrlen() не имеет побочные эффекты и, следовательно, он может повторно использовать старый результат от mystrlen(text) вместо вызова его дважды.

Я не нахожу ничего в документах об этом и restrict, либо одна из его дисперсий, похоже, не выполняет эту работу. Взгляд на выходной код со всеми оптимизациями (переключатель /Ox) показывает, что компилятор действительно генерирует два вызова. Это даже делает, если я поместил обе функции в один модуль.

Любое решение этого или может кто-нибудь подтвердить, что в VC++ нет решения?

+0

Вы хотите более функциональный язык. – SLaks

+0

Это делает это (назовите это дважды), даже если вы включите всю оптимизацию? И что, если он находится в одном исходном файле? Еще такой же результат? – Floris

+0

@Floris: Я использовал '/ Ox', и даже если в одном модуле он дважды выполняет функцию. – cxxl

ответ

-1

Поскольку C++ - это императивный язык, а не функциональный, то, чего вы пытаетесь достичь, невозможно.

Похоже, что поведение, которое вы ожидаете здесь, - это то, что связано с ссылочной прозрачностью, о котором не говорится в компиляторе на C++ (но на чисто функциональном языке программирования, таком как Haskell, будет подразумеваться) ,

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

+2

Я не понимаю, почему императивные и функциональные имеют какое-либо отношение к тому, чтобы определенная функция не имеет побочных эффектов (т.е. последствий для других объектов). Без сомнения, он будет реализован на C++. Вопрос в том, _is_ это? – cxxl

0

То, что вы ищете, не поможет.

В общем, компилятор не может преодолеть вызовы, даже если, если полагает, что функция не имеет побочных эффектов. Откуда у вас этот указатель? Имеет ли обработчик сигнала доступ к тому же указателю? Может, другой поток? Как компилятор знает, что память, на которую указывает указатель, не изменится из-под нее?

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

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

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

Например:

// b.cpp 
extern int mystrlen(const char*); 
int foo(int bar) { 
    char number[20]; 
    snsprintf(number, 20, "%d", bar); 
    return mystrlen(number) + mystrlen(number); 
} 

С учетом предположения компилятор может сделать о том, что snprintf сделал с number, учитывая, что это функция библиотеки, она может затем Elide второй вызов mystrlen, если есть способ, чтобы объявить mystrlen не имел побочных эффектов.

 Смежные вопросы

  • Нет связанных вопросов^_^