Встроенные методы C++ с одинаковыми операторами if
-
25-09-2019 - |
Вопрос
Я пишу обработчик для текстур OpenGL и думаю о безопасности и производительности.На каком уровне оптимизации следует удалить отмеченные операторы if?
struct Texture2D {
GLuint ID;
inline Texture2D(): ID(0) {};
inline explicit Texture2D(GLuint id): ID(id) {};
~Texture2D();
void GenTexture(bool regen = false);
void DeleteTexture();
void BindTexture();
void Parameterf( GLenum pname, GLfloat param );
void Parameteri( GLenum pname, GLint param );
void glTexParameterfv( GLenum target, GLenum pname, const GLfloat *params );
void glTexParameteriv( GLenum target, GLenum pname, const GLint *params );
static Texture2D binded;
};
inline void Texture2D::GenTexture(bool regen) {
if(ID){
if(regen)
DeleteTexture();
else
return;
}
glGenTextures(1,&ID);
}
inline void Texture2D::DeleteTexture() {
glDeleteTextures(1,&ID);
ID = 0;
}
inline void Texture2D::BindTexture() {
glBindTexture(GL_TEXTURE_2D, ID);
binded.ID = ID;
}
inline void Texture2D::Parameterf( GLenum pname, GLfloat param ){
if(binded.ID == ID) // THIS
BindTexture(); // THIS
glTexParameterf(GL_TEXTURE_2D,pname,param);
}
inline void Texture2D::Parameteri( GLenum pname, GLint param ){
if(binded.ID == ID) // THIS
BindTexture(); // THIS
glTexParameterf(GL_TEXTURE_2D,pname,param);
}
inline Texture2D::~Texture2D() {
DeleteTexture();
}
// in this function
void loadTexture(...) {
Texture2D t;
t.GenTexture();
t.BindTexture();
// if statements in next functions
t.Parameterf(...);
t.Parameterf(...);
t.Parameterf(...);
t.Parameterf(...);
t.Parameterf(...);
}
Решение
Никто.
Печальная история, но C++ предполагает, что если вы вызываете функцию, то эта функция может вызвать всевозможные побочные эффекты, включая изменение значения Bind.ID (о чем функция каким-то образом знает).
Кроме
Если вы убедитесь, что вызываемые вами функции не имеют абсолютно никакого законного способа узнать о вашем bindend.ID
, либо напрямую (ссылаясь на него), либо косвенно (потому что кто-то другой взял указатель на него и передал его).Вот простой пример (предполагая, что side_effect()
находится в другой единице перевода)
int side_effect();
int k=1;
int main()
{
side_effect();
if (k!=0) return 0;
side_effect();
if (k!=0) return 0;
side_effect();
if (k!=0) return 0;
}
side_effect()
можно использовать и менять k
юридически, объявив его внешним.Нет звонка side_effect
можно оптимизировать.
int side_effect();
static int k=1;
int main()
{
side_effect();
if (k!=0) return 0;
side_effect();
if (k!=0) return 0;
side_effect();
if (k!=0) return 0;
}
Это невозможно для side_effect
чтобы получить доступ k
разрешенным способом, поскольку вы не можете получить доступ к статике в другой единице перевода.Поэтому код можно оптимизировать для side_effect(); return 0
потому что k не изменится, пока Side_effect() не ковыряется в памяти.Конечно, это было бы неопределенное поведение.
int side_effect();
void snitch(int*);
static int k=1;
int main()
{
snitch(&k); // !!!
side_effect();
if (k!=0) return 0;
side_effect();
if (k!=0) return 0;
side_effect();
if (k!=0) return 0;
}
Компилятор не имеет возможности узнать, если snitch()
сохраняет свой аргумент в месте, где side_effect()
может изменить его, поэтому нет вызова side_effect()
можно устранить.
Вы получите ту же ситуацию, если у вас есть k
как локальная переменная:Если существует вероятность того, что какая-то неизвестная процедура сможет получить доступ k
законным способом, то компилятор не сможет проводить оптимизацию на основе значения k.
ПС: Изготовление k
const не помогает, потому что отбросить константу можно.const-ness не может использоваться в качестве подсказки по оптимизации.
Другие советы
Это будет зависеть от компилятора, и ваша лучшая ставка - проверять - компилировать и проверять излучаемый машинный код.
Ни один уровень оптимизации не может (правильно) Удалить эти тесты. Они могут быть удалены только в том случае, если оба аргумента были константами времени компиляции, и ни один из них не являются, либо если компилятор может доказать, что они не будут изменять значение между тестами.
С binded
Статичен, компилятор не может знать, что вызовы функций GL не изменит его.