2012-05-04 14 views
5

Ho una classe template definita come:C++ "new T [size]" non funziona?

#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); 
     } 
    } 

e ad un certo punto nel costruttore che faccio:

m_buffer = new T[size]; 

Questo funziona per la maggior parte dei casi d'uso, ma in una prova ottengo il seguente memoria errore segnalato da valgrind (comando e snippet pertinente sotto) il test passa comunque bene. Il bit interessante è operator new(unsigned long) che significa che non si sta allineando e allineando per il calcestruzzo di tipo T l'installazione "double" come mi aspettavo ma per unsigned long? Se modifico l'implementazione del bufferpool e l'hard-code new double[size], questo errore di memoria non viene visualizzato, ma ovviamente funziona solo con tbufferpool<double> ora.

Qualcuno può consigli su come risolvere questo problema? il new T[size] dovrebbe essere legale giusto? poiché i parametri del modello vengono applicati in fase di compilazione dal pre-processore che crea una nuova classe per ogni tipo di modello utilizzato. Questo sarebbe un bug del compilatore?

test_matrix è una suite contenente 30 casi di test. Solo un test produce il problema mostrato di seguito in valgrind, che tuttavia il test passa. Ho controllato tutti gli ingressi per la chiamata di funzione in cui il problema ha origine utilizzando la variante new T[size] e li ho stampati insieme agli stessi input utilizzando la variante new double[size]. Li paragono usando AraxisMerge e sono identici. Temo che un problema legato all'allineamento della memoria sia diverso a seconda che utilizzi il parametro template o il tipo double 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] 

dettagli di 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 pensiero, ma forse perché 'double' ha le stesse dimensioni di' unsigned long'. – Tibor

+3

Si prega di provare ad isolare il problema (una istanziazione del modello 'tbufferpool' con tipo double, rimuovere il più possibile dal costruttore) e ripubblicare il codice. La cosa più importante è il modo in cui 'size' è inizializzato. –

+0

Ciò significa che non hai inizializzato parte della memoria allocata, ma avresti dovuto farlo. Stai inizializzando quella memoria allocata? – mfontanini

risposta

4

Si prega di notare la differenza tra

m_buffer = new T[size]; 

e

m_buffer = new T[size](); 

Nel primo caso la matrice non è inizializzata, quindi il vostro valgrind errore:

Conditional jump or move depends on uninitialised value 

Detto questo, in base alla mia esperienza, in questo caso è possibile ignorare questa particolare uscita valgrind. Come ovviamente usi una specie di implementazione blas, molto probabilmente è l'effetto di un'ottimizzazione all'interno della tua libreria BLAS e non farai cose cattive.

+0

wow fantastico! i tuoi suggerimenti risolvono il problema! Sto usando g ++ e gcc ultima versione in Mac OS X 4.6.3 –

2

Il problema non riguarda l'assegnazione di memoria di per sé. Valgrind dice che stai usando i valori unitializzati dalla matrice puntata da m_buffer. È possibile ottenere lo stesso con

 

T value; 
// use value 
 

o

 

T values[size]; 
// use values 
 

Per risolvere il problema è necessario inizializzare il buffer con valori appropriati dopo l'allocazione della memoria, per esempio

 

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 semplicemente usare invece std :: vector.

Problemi correlati