5

次のように定義されたテンプレートクラスがあります。

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

コンストラクターのある時点で、私は次のことを行います。

m_buffer = new T[size];

これはほとんどのユースケースで機能しますが、1つのテストで、valgrindによって報告された次のメモリエラー(以下のコマンドと関連するスニペット)が表示されますが、テストは正常に合格します。興味深いoperator new(unsigned long)点は、私が期待したように「ダブル」に設定した具体的なTタイプに割り当てたり、位置合わせしたりしていないことを意味しますが、unsigned long?バッファプールの実装とハードコードを変更するとnew double[size]、このメモリエラーは表示されませんが、もちろんtbufferpool<double>現在は作業しているだけです。

誰かがこれを修正する方法をアドバイスできますか?法的な権利であるnew T[size]必要がありますか?テンプレートパラメータは、使用されるテンプレートタイプごとに新しいクラスを作成するプリプロセッサによってコンパイル時に適用されるためです。これはコンパイラのバグでしょうか?

test_matrixは、30個のテストケースを含むスイートです。valgrindで以下に示す問題が発生するテストは1つだけですが、それでもテストは合格です。バリアントを使用して問題が発生した関数呼び出しへのすべての入力を確認し、new T[size]バリアントを使用して同じ入力と一緒に出力しましたnew double[size]。AraxisMergeを使用してそれらを比較しましたが、同じです。テンプレートパラメータを使用するか、具象ダブルタイプを使用するかによって、メモリアライメントが異なることに関連する問題が発生するのではないかと思います...?

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

システムの詳細:

/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.
4

2 に答える 2

4

の違いに注意してください

m_buffer = new T[size];

m_buffer = new T[size]();

前者の場合、配列が初期化されていないため、valgrind エラーが発生します。

Conditional jump or move depends on uninitialised value

そうは言っても、私の経験から、この場合、この特定の valgrind 出力を無視できます。明らかにある種の blas 実装を使用しているため、BLAS ライブラリ内の最適化の効果である可能性が高く、悪いことはしません。

于 2012-05-04T11:37:46.267 に答える
2

あなたの問題は、メモリ割り当て自体には関係ありません。Valgrind は、 が指す配列の単​​位化された値を使用していると言っていますm_buffer。あなたは同じことを得ることができます


T value;
// use value

また


T values[size];
// use values

この問題を解決するには、メモリ割り当て後に適切な値でバッファを初期化する必要があります。


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


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

または、代わりに std::vector を使用してください。

于 2012-05-04T11:38:44.020 に答える