c++ types wrapper typedef portability

Contenedor de clase C++ alrededor de tipos fundamentales



types wrapper (3)

Muchas bibliotecas que he visto / usado tienen typedefs para proporcionar variables portátiles, de tamaño fijo, por ejemplo, int8, uint8, int16, uint16, etc. que tendrán el tamaño correcto independientemente de la plataforma (y c ++ 11 lo hace con el stdint del encabezado). h)

Después de usar recientemente archivos binarios de E / S en una pequeña biblioteca que estoy escribiendo, puedo ver el beneficio de usar typedefs de esta manera para asegurar que el código sea portátil.

Sin embargo, si me tomo la molestia de escribir "namespace :: uint32" en lugar de utilizar tipos fundamentales incorporados, también puedo hacer que el reemplazo sea lo más útil posible. Por lo tanto, estoy considerando usar clases en lugar de simples typedefs.

Estas clases contenedoras implementarían todos los operadores normales, por lo que podrían usarse indistintamente con el tipo fundamental.

P.ej:

int x = 0; //do stuff

podría convertirse

class intWrapper { //whatever }; intWrapper = 0; //do stuff

sin tener que modificar ningún código en "// hacer las cosas"

La razón por la que estoy considerando este enfoque en comparación con solo typedefs es el hecho de que ya tengo funciones que operan en tipos fundamentales, por ejemplo

std::string numberToString(double toConvert); std::string numberToHexString(double toConvert); int intToXSignificantPlaces(const int& number, unsigned char numberOfSignificantPlaces); bool numbersAreApproximatelyEqual(float tollerance); //etc....

Desde el punto de vista sintáctico, sería más agradable (y más fácil) hacer lo siguiente:

intWrapper.toString(); intWrapper.toHexString(); //etc

También me permitiría implementar clases bigint (int128, etc.) y tener esas y las más pequeñas (basadas en tipos fundamentales) usar interfaces idénticas.

Finalmente, cada contenedor podría tener una instancia estática de sí misma llamada max y min, por lo que la sintaxis agradable de int32 :: max e int32 :: min sería posible.

Sin embargo, tengo algunas inquietudes que me gustaría abordar antes de hacer esto (dado que se trata principalmente de azúcar sintáctica y estos tipos se utilizarían, por lo que cualquier sobrecarga adicional podría tener un impacto significativo en el rendimiento).

1) ¿Hay alguna función adicional que llame a gastos generales cuando se utiliza algúnClass.operator + (), someClass.operator- () etc sobre solo int a + int b? De ser así, ¿el operador de línea + () eliminaría TODA esta sobrecarga?

2) Todas las funciones externas requieren el tipo primitivo, por ejemplo, glVertex3f (float, float, float) simplemente no se pueden pasar 3 objetos floatWrapper, ¿hay alguna forma de hacer que el compilador lance automáticamente el floatWrapper a un float? Si es así, ¿hay impactos en el rendimiento?

3) ¿Hay algún gasto de memoria adicional? Entiendo (?) Que las clases con herencia tienen algún tipo de puntero de tabla virtual, así que use un poco más de memoria (¿o solo para funciones virtuales?), Pero suponiendo que estas clases de envoltura no se hereden de / no sean clases secundarias, no hay t uso de memoria adicional utilizando clases en lugar de tipos fundamentales, ¿verdad?

4) ¿Hay algún otro problema / impacto en el rendimiento que esto pueda causar?


1) ¿Hay alguna función adicional que llame a gastos generales cuando se utiliza someClass.operator + ()

No, si el cuerpo de la función es pequeño y está en el encabezado, estará en línea y no tendrá gastos generales

2) ¿Hay alguna manera de hacer automáticamente que el compilador arroje el floatWrapper a un flotador?

struct floatWrapper { floatWrapper(float); //implicit conversion from float operator float(); //implicit conversion to float. };

De nuevo, si el cuerpo de la función es pequeño y está en el encabezado, estará en línea y no tendrá gastos generales.

3) ¿Hay algún gasto de memoria adicional?

no si no hay funciones virtuales Una clase se llama polimórfica si declara o hereda cualquier función virtual. Si una clase no es polimórfica, los objetos no necesitan incluir un puntero a una tabla de funciones virtuales. Además, no se permite realizar la transmisión dinámica de un puntero / referencia a una clase no polimórfica por la jerarquía de herencia a un puntero / referencia a una clase derivada, por lo que no es necesario que los objetos tengan algún tipo de información de tipo.

4) ¿Hay algún otro problema / impacto en el rendimiento que esto pueda causar?

¿actuación? No.

Además, asegúrese de implementar operadores binarios que no modifiquen lhs como funciones libres, y sobrecargúelos para admitir todas las permutaciones relevantes de floatWrapper y float .

struct floatWrapper { explicit floatWrapper(float); operator float(); //implicit conversion to float. floatWrapper operator-=(float); }; floatWrapper operator-(floatWrapper lhs, floatWrapper rhs) {return lhs-=rhs;} floatWrapper operator-(float lhs, floatWrapper rhs) {return floatWrapper(lhs)-=rhs;} floatWrapper operator-(floatWrapper lhs, float rhs) {return lhs-=rhs;}

Aquí está mi intento de tal cosa . Tenga en cuenta que necesitará una versión ligeramente diferente para doble flotante / doble / largo.


Creo que las respuestas no son del todo correctas, al menos para gcc 4 He observado una sobrecarga significativa debido a las llamadas del constructor y del operador.

Lo siguiente toma aproximadamente el doble de tiempo que con el long :

typedef intWrapperImpl<long> TestWrapper; //typedef long TestWrapper; int main (int argc, char** argv) { TestWrapper sum(0); TestWrapper test(4); for (long i = 0; i < 1000000000L; ++i) { sum += test; } cout << sum << "/n"; return 0; }

El uso de diferentes versiones de gcc 4 con y sin optimización no generó diferencias en el rendimiento.

En este caso, agregando

intWrapperImpl& operator+=(const intWrapperImpl & v) {value+=v.value; return *this;}

solo da una ligera mejora.

Usar una envoltura como si fueran tipos básicos en código crítico de rendimiento parece ser una mala idea. Usarlos localmente e invocar al constructor todo el tiempo parece incluso peor.

Esto realmente fue una sorpresa para mí, ya que fácilmente podría ser posible alinear todo y optimizarlo como si fuera una variable de tipo base.

¡Cualquier sugerencia adicional sería muy apreciada!


Depende del compilador. Si tiene bucles o asignaciones, es menos probable que esté en línea.