2012-05-04 11 views
5

ich eine Template-Klasse haben wie folgt definiert:C++ "neue T [Größe]" funktioniert nicht?

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

und irgendwann im Konstruktor ich tun:

m_buffer = new T[size]; 

Dies funktioniert für die meisten Anwendungsfälle aber in einem Test habe ich den folgenden Speicher Fehler, der von Valgrind gemeldet wurde (Befehl und relevanter Ausschnitt unten), der Test ist jedoch noch in Ordnung. Das interessante Bit ist operator new(unsigned long) was bedeutet, dass es nicht für die konkrete T-Typ-I-Setup "double" wie ich erwartet, sondern für unsigned long Zuordnung und Ausrichtung? Wenn ich meine Pufferpool-Implementierung und hard-Code new double[size] ändern, dann wird dieser Speicherfehler nicht angezeigt, aber natürlich arbeite ich nur mit tbufferpool<double> jetzt.

Kann jemand Ratschläge wie man das beheben? die new T[size] sollte legal sein? da die Template-Parameter zur Kompilierzeit vom Pre-Prozessor angewendet werden, der für jeden verwendeten Template-Typ eine neue Klasse erstellt. Wäre das ein Compilerfehler?

Die test_matrix ist eine Suite mit 30 Testfällen. Nur ein Test erzeugt das unten gezeigte Problem in Valgrind, dieser Test besteht trotzdem. Ich überprüfte alle Eingaben für den Funktionsaufruf, bei dem das Problem auftritt, unter Verwendung der new T[size] Variante und druckte sie neben den gleichen Eingaben unter Verwendung der new double[size] Variante. Ich vergleiche sie mit AraxisMerge und sie sind identisch. Ich fürchte, es ist ein Problem, das mit der Speicherausrichtung zusammen hängt, je nachdem, ob ich den Template-Parameter oder den konkreten Doppeltyp verwende ...?

$ 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] 

System:

/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

Nur ein Gedanke, aber vielleicht liegt es daran, dass 'double' genauso groß ist wie' unsigned long'. – Tibor

+3

Bitte versuchen Sie das Problem zu isolieren (eine Instantiierung der 'tbufferpool' Vorlage mit dem Typ double, entfernen Sie soviel wie möglich aus dem Konstruktor) und wiederholen Sie den Code. Am wichtigsten ist, wie 'Größe' initialisiert wird. –

+0

Das bedeutet, dass Sie einen Teil des zugewiesenen Speichers nicht initialisiert haben, aber Sie sollten es getan haben. Initialisieren Sie diesen zugewiesenen Speicher? – mfontanini

Antwort

4

Bitte beachten Sie den Unterschied zwischen

m_buffer = new T[size]; 

und

m_buffer = new T[size](); 

Im ersteren Fall das Array nicht initialisiert wird, damit Ihre valgrind Fehler:

Conditional jump or move depends on uninitialised value 

Das sagte, aus meiner Erfahrung können Sie diese bestimmte Valgrind-Ausgabe in diesem Fall ignorieren. Da Sie offensichtlich eine Art von blas-Implementierung verwenden, ist es höchstwahrscheinlich der Effekt einer Optimierung innerhalb Ihrer BLAS-Bibliothek und wird keine schlechten Dinge tun.

+0

wow fantastisch! Ihre Vorschläge lösen das Problem! Ich benutze g ++ und gcc neueste Version in Mac OS X 4.6.3 –

2

Ihr Problem bezieht sich nicht auf die Speicherzuordnung per se. Valgrind sagt, dass Sie unitäre Werte von dem Array verwenden, auf das m_buffer zeigt. Sie können das gleiche mit

 

T value; 
// use value 
 

oder

 

T values[size]; 
// use values 
 

erhalten, um das Problem zu beheben Sie benötigen, um Ihre Puffer mit den entsprechenden Werten nach Speicherzuweisung zu initialisieren, z.B.

 

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

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

oder nur statt std :: vector verwenden.

Verwandte Themen