2012-05-04 15 views
5

He una clase de plantilla definida como:C++ "new T [size]" no funciona?

#include <stdio.h> 
#include <queue> 

using namespace std; 

template<class T> 
class tbufferpool { 
private: 
    const int m_initial; 
    const int m_size; 
    const int m_total; 
    T *m_buffer; 
    vector<T*> m_queue; 

public: 
    // constructor 
    tbufferpool(int initial, int size) : m_initial(initial), m_size(size), m_total(initial*size) { 
     m_buffer = new T[m_total]; 
     T* next_buffer = m_buffer; 
     for (int i = 0; i < initial; ++i, next_buffer += size) { 
      m_queue.push_back(next_buffer); 
     } 
    } 

y en algún momento en el constructor que hago:

m_buffer = new T[size]; 

Esto funciona para la mayoría de los casos de uso, pero en una prueba me sale el siguiente memoria error reportado por valgrind (comando y fragmento relevante a continuación) la prueba todavía es correcta. El bit interesante es operator new(unsigned long), lo que significa que no se está asignando y alineando para la configuración concreta tipo T "doble", como esperaba, pero para unsigned long? Si modifico la implementación de mi grupo de almacenamiento intermedio y el código duro new double[size], este error de memoria no se muestra, pero por supuesto ahora solo trabajo con tbufferpool<double> ahora.

¿Alguien puede aconsejar cómo solucionar esto? el new T[size] debería ser legal ¿verdad? ya que los parámetros de la plantilla se aplican en tiempo de compilación por el pre-procesador que crea una nueva clase para cada tipo de plantilla utilizada. ¿Sería esto un error del compilador?

Test_matrix es una suite que contiene 30 casos de prueba. Solo una prueba produce el problema que se muestra a continuación en valgrind, sin embargo, la prueba pasa. Comprobé todas las entradas a la llamada de función donde se origina el problema usando la variante new T[size] y las imprimí junto a las mismas entradas usando la variante new double[size]. Los comparo usando AraxisMerge y son idénticos. Me temo que un problema relacionado con la alineación de la memoria es diferente dependiendo de si utilizo el parámetro de plantilla o el tipo doble concreto ...?

$ valgrind --show-reachable=yes --dsymutil=yes --track-origins=yes ./test_matrix 
    [snip] 
    ==3719== Conditional jump or move depends on uninitialised value(s) 
    ==3719== at 0x3BE86C8: mkl_blas_dscal (in /opt/intel/composerxe-2011.4.184/mkl/lib/libmkl_mc3.dylib) 
    ==3719== by 0x432FFFFFFFFFFFFF: ??? 
    ==3719== Uninitialised value was created by a heap allocation 
    ==3719== at 0xD62F: malloc (vg_replace_malloc.c:266) 
    ==3719== by 0x97B15C: operator new(unsigned long) (in /opt/local/lib/gcc46/libstdc++.6.dylib) 
    ==3719== by 0x7FFF5FBFE54F: ??? 
    ==3719== by 0x10014BDBF: ??? 
    ==3719== by 0x7FFF5FBFE58F: ??? 
    ==3719== by 0x97B288: operator new[](unsigned long) (in /opt/local/lib/gcc46/libstdc++.6.dylib) 
    ==3719== by 0x7FFF5FBFE58F: ??? 
    ==3719== by 0x100013853: tbufferpool<double>::tbufferpool(int, int) (bufferpool.h:30) 
    ==3719== by 0x7003FFFFF: ??? 
    ==3719== by 0x100079E7F: ??? (in ./test_matrix) 
    ==3719== by 0x7FFF5FBFE58F: ??? 
    ==3719== by 0x10014BE0F: ??? 
    ==3719== 
    ==3719== Conditional jump or move depends on uninitialised value(s) 
    ==3719== at 0x3BE86CA: mkl_blas_dscal (in /opt/intel/composerxe-2011.4.184/mkl/lib/libmkl_mc3.dylib) 
    ==3719== by 0x432FFFFFFFFFFFFF: ??? 
    ==3719== Uninitialised value was created by a heap allocation 
    ==3719== at 0xD62F: malloc (vg_replace_malloc.c:266) 
    ==3719== by 0x97B15C: operator new(unsigned long) (in /opt/local/lib/gcc46/libstdc++.6.dylib) 
    ==3719== by 0x7FFF5FBFE54F: ??? 
    ==3719== by 0x10014BDBF: ??? 
    ==3719== by 0x7FFF5FBFE58F: ??? 
    ==3719== by 0x97B288: operator new[](unsigned long) (in /opt/local/lib/gcc46/libstdc++.6.dylib) 
    ==3719== by 0x7FFF5FBFE58F: ??? 
    ==3719== by 0x100013853: tbufferpool<double>::tbufferpool(int, int) (bufferpool.h:30) 
    ==3719== by 0x7003FFFFF: ??? 
    ==3719== by 0x100079E7F: ??? (in ./test_matrix) 
    ==3719== by 0x7FFF5FBFE58F: ??? 
    ==3719== by 0x10014BE0F: ??? 
    [snip] 

detalles del sistema:

/Users/bravegag/code/fastcode_project/build_debug$ uname -a && g++ --version 
Darwin Macintosh-4.local 11.3.0 Darwin Kernel Version 11.3.0: Thu Jan 12 18:47:41 PST 2012; 
root:xnu-1699.24.23~1/RELEASE_X86_64 x86_64 
g++ (GCC) 4.6.3 
Copyright (C) 2011 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+0

Solo un pensamiento, pero tal vez es porque 'double' es del mismo tamaño que' unsigned long'. – Tibor

+3

Intente aislar el problema (una instanciación de la plantilla 'tbufferpool' con tipo double, elimine la mayor cantidad posible del constructor) y vuelva a publicar el código. Lo más importante es cómo se inicializa 'size'. –

+0

Eso significa que no ha inicializado una parte de esa memoria asignada, pero debería haberlo hecho. ¿Estás inicializando esa memoria asignada? – mfontanini

Respuesta

4

Tenga en cuenta la diferencia entre

m_buffer = new T[size]; 

y

m_buffer = new T[size](); 

En el primer caso la matriz no es inicializado, por lo tanto, su valgrind error:

Conditional jump or move depends on uninitialised value 

Dicho esto, desde mi experiencia puede ignorar esta salida particular de valgrind en este caso. Como obviamente usa algún tipo de implementación de blas, lo más probable es que sea el efecto de una optimización dentro de su biblioteca BLAS y no haga cosas malas.

+0

guau fantástico! ¡tus sugerencias resuelven el problema! Estoy usando la última versión de g ++ y gcc en Mac OS X 4.6.3 –

2

Su problema no se relaciona con la asignación de memoria per se. Valgrind dice que está utilizando valores unificados de la matriz apuntada por m_buffer. Usted puede conseguir lo mismo con

 

T value; 
// use value 
 

o

 

T values[size]; 
// use values 
 

Para solucionar el problema que necesita para inicializar la memoria intermedia con valores adecuados después de la asignación de memoria, por ejemplo,

 

m_buffer = new T[size]; 
std::fill_n(m_buffer, size, T()); 
 
 

m_buffer = new T[size](); // doesn't work in gcc3.x.x 
 

o simplemente utilizar std :: vector en su lugar.

Cuestiones relacionadas