En este post traigo una lista de preguntas frecuentes que he ido encontrando en las entrevistas que he ido haciendo durante mis primeros años , normalmente para posiciones de Junior Gameplay Programmer / C++.

Añadir que todas mis respuestas están abiertas a debate y corrección! No dudéis en completar o corregir mis respuestas si veis fallos o inconsistencias! ⚠️🪲👨‍💻 La mejor información se obtiene de muchas fuentes! 📚📚🗣️🗣️

💬 ¿cuál es la diferencia entre ‘struct’ y ‘class’?

la diferencia más destacable es que en class los miembros y la herencia son privados por defecto. Además de ofrecer mejores herramientas para la abstracción. Normalmente los structs se usan para datos puros y ya, mientras que class se usan cuando hay lógica detrás.

💬 ¿cómo podrías saber si un int es impar ?

con el operador módulo %

if(n % 2 != 0) { /*n es impar*/ }

💬 ¿qué opinas de llamar a métodos virtuales en el constructor?

es peligroso ya que dentro del constructor, el sistema de herencia no ha sobrescrito aún las funciones virtuales. Por tanto se llamará únicamente a la versión base del método.

💬 ¿que opinas de llamar a ‘delete this’?

lo peor de todo es que ‘delete this’ funciona. Recomendable no usarlo jamás obviamente, pero si se usa, recordad no acceder al objeto más, a partir de esa línea ಠ_ಠ

💬 ¿qué es el polimorfismo y para qué se usa?

este concepto significa que puedes acceder a diferentes objetos mediante la misma interfaz, siempre que las clases de esos objetos, hereden o implementen esa interfaz común claro.

💬 ¿de dónde viene el ‘overhead’ de las funciones virtuales?

pueden introducir un ligero deterioro del rendimiento debido a que son resueltas en runtime mediante una tabla de definiciones (vtable).Lo cual añade un nivel de indirección que afecta al branch predictor de la cpu.

💬 ¿diferencias entre malloc y new?

new operador de c++, no requiere el núm. de bytes a reservar, devuelve un puntero al tipo reservado, llama al constructor del objeto.

malloc es una función de c, requiere núm. de bytes, retorna void*, no llama al constructor.

(Entre otras)

💬 ¿cuál es el uso del dot product?

En espacios 2D-3D el valor del dot product nos indica las direcciones relativas de ambos vectores mediante un valor. Si el valor es 1, apuntan en la misma dirección, -1 si opuesto y 0 si son perpendiculares.

💬 ¿cuál es el uso del cross product?

el cross product retorna un vector perpendicular a los dos vectores introducidos. Dependiendo del sistema de coordenadas y de la rotación de los vectores, el vector perpendicular puede tener una dirección o la opuesta (+1, -1)

💬 ¿si te dieran la tarea de mejorar el framerate, que sería lo PRIMERO que harías?

esta la lanzo al público, me apareció en una entrevista y me gustó mucho 😂

Lo primero, buscar que partes son las que más tiempo del frame se están llevando con herramientas de profiling, para centrarme en ellas. También asegurarme de batchear geometría, occlusions varios, si hay streaming de datos muy masivos y checkear el núm. de AIs 🐣 Simplemente porque son los bottleneck que más he encontrado en mi carrera.

💬 ¿cuál es la diferencia entre ++i, i++ y i+=1?

importante el orden de las operaciones:

  • ++i suma 1 a i y retorna el valor
  • i++ retorna el valor y DESPUÉS suma 1 al valor
  • i+=1 es equivalente a ++i

💬 ¿qué es el ‘time complexity’ de un algoritmo?

Es un ‘orden de magnitud’ que nos indica cuál es el coste en tiempo de un algoritmo. (Ver: Big O Notation)

El orden de magnitud suele venir dado por el tamaño del input del algoritmo.

💬 ¿cuál es el time complexity de ‘imprimir todos los nodos de un binary tree’? 🌲

O(n). Ya que se recorre 1 sola vez todo el conjunto de n nodos.

O(n) se le denomina ‘Linear Time’.

💬 ¿debería un game engine usar la STL de C++?

esta es una pregunta histórica y no tengo respuesta, la STL tiene ventajas y desventajas claro. Aunque las desventajas en mi opinión afloran cuando quieres alcanzar cotas de rendimiento AAA+. Hace una década la STL era mucho más limitada y con muchos más problemas entre plataformas e interoperabilidad con C, que la versión actual. Desde C++ 11 la cosa ha ido mejorando mucho hasta la versión actual que te ofrece un montón de opciones muy sólidas.

Es sabido que EA tiene (o tenía) su EA STL, la cual era una reimplementación in-house de la STL de C++. Unreal por ejemplo, implementa su propia librería de containers.

Como ejemplo práctico tomaré la clase std::vector, un array dinámico que va reservando memoria automáticamente, std::vector inicia con una memoria inicializada por defecto, cuando se llena, se reserva más y se reubican los elementos. Esto tiene un coste pero ganamos la capacidad de tener un array dinámico. Es esto una desventaja, depende del caso, si no quieres que esto ocurra en tu engine, por X razón, entonces te tocará usar otra estructura de datos o reimplementar la clase vector.

💬 ¿cuál es la diferencia entre un puntero y un array?

puntero es un valor que almacena una dirección de memoria. Array es una colección de valores secuenciales almacenados en memoria.

un puntero puede apuntar a la posición inicial de un array, lo cual puede confundir.

💬 ¿qué es un ‘design pattern’ y por qué son útiles?

son soluciones que explotan ciertos beneficios estructurales del código en pos de generar un código mantenible. Además otras personas pueden reconocer estos patrones (de ahí su nombre) mejorando la legibilidad y la posibilidad de que el código sea mantenido y extendido por otras personas.

💬 ¿cuál es la diferencia entre & y &&?

& es ‘bitwise AND’ y && es un ‘logical AND’

& puede ser usado también como operador lógico, pero la ventaja de && es que solo checkea la parte más izquierda de la expresión booleana y si es false, no sigue, muy conveniente.

💬 ¿qué hace la keyword ‘mutable’? menciona un caso de uso

mutable se usa para indicar que un miembro de una clase puede cambiar su valor ignorando las etiquetas const del método en el que se modifica. Su uso puede indicar un mal diseño, pero puede ser usado correctamente por ejemplo para cachear valores. Imaginemos que tenemos un contenedor custom, que tiene una función get(int index) const, esa función puede modificar el miembro mCache, con el último valor accedido y si se vuelve a acceder, podemos devolver mCache en lugar de buscarlo otra vez.

💬 ¿qué es un ‘quadtree’? menciona un caso de uso.

estructura de datos que subdivide el espacio en regiones cuadradas 2D (si es 3D es un octree). Puede subdividirse un nivel N de veces, hasta alcanzar el tamaño mínimo permitido para los nodos hoja.

Un caso de uso podría ser checkear las colisiones entre colliders de una escena. Por fuerza bruta comprobamos NxN colliders. Pero realmente no tiene sentido comprobar si dos colliders están colisionando si están muy lejos. Un quadtree nos permite agrupar objetos en pequeñas regiones de tal forma que podemos reducir la cantidad de parejas de colliders a comprobar. De tal forma que si en un nodo hoja del quadtree solo tenemos 1 collider, podemos asegurar que no va a colisionar con nada en este punto del tiempo. Podemos ignorar el nodo.

Si tenemos 2 o más colliders en un nodo entonces podemos proceder a comprobar colisiones entre pares.

Aquí un ejemplo visual de como funciona el quadtree implementado en mi engine Druid :)

Ahí se ve como va actualizando nodos hoja en función de si tienen o no objetos dentro.