memcopy durch std::copy ersetzen.



  • Ich bin in meinem letzten Post darauf hingewiesen worden, dass ich doch memcopy durch std::copy ersetzten könnte, selbst wenn ich dabei nur mit C-Arrays arbeite oder diese mit vector Arrays mische.

    Jetzt habe ich das ausprobiert und es klappt nicht, weil die Typen unterschiedlich sind:

    std::copy(InArray.begin(), InArray.end(), in);
    	//memcpy(in,InArray, m_size.x  * sizeof(complex<double>));
    

    mit

    vector<complex<double> > & InArray
    fftw_complex *in
    

    liefert den Fehler:

    1>C:\Programme\Microsoft Visual Studio 8\VC\include\xutility(2266) : error C2440: '=': 'std::complex<double>' kann nicht in 'double [2]' konvertiert werden
    1> Kein benutzerdefinierter Konvertierungsoperator verfügbar, der diese Konvertierung durchführen kann, oder der Operator kann nicht aufgerufen werden
    1> C:\Programme\Microsoft Visual Studio 8\VC\include\xutility(2279): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "_OutIt std::_Copy_opt<_InIt,double(),std::forward_iterator_tag>(_InIt,_InIt,_OutIt,_InOutItCat,std::_Nonscalar_ptr_iterator_tag,std::_Range_checked_iterator_tag)".
    1> with
    1> [
    1> _OutIt=double (
    ),
    1> _InIt=std::_Vector_iterator<std::complex<double>,std::allocator<std::complex<double>>>,
    1> _InOutItCat=std::forward_iterator_tag
    1> ]
    1> C:\Programme\Microsoft Visual Studio 8\VC\include\xutility(2373): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "_OutIt std::_Copy_opt<std::_Vector_iterator<_Ty,_Alloc>,_OutIt>(_InIt,_InIt,_OutIt,std::random_access_iterator_tag,std::_Nonscalar_ptr_iterator_tag,std::_Range_checked_iterator_tag)".
    1> with
    1> [
    1> _OutIt=fftw_complex (),
    1> _Ty=std::complex<double>,
    1> _Alloc=std::allocator<std::complex<double>>,
    1> _InIt=std::_Vector_iterator<std::complex<double>,std::allocator<std::complex<double>>>
    1> ]
    1> .\include\fftw\QFFTW.cpp(168): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "double (*std::copy<std::_Vector_iterator<_Ty,_Alloc>,fftw_complex(*)>(_InIt,_InIt,_OutIt))".
    1> with
    1> [
    1> _Ty=std::complex<double>,
    1> _Alloc=std::allocator<std::complex<double>>,
    1> _InIt=std::_Vector_iterator<std::complex<double>,std::allocator<std::complex<double>>>,
    1> _OutIt=fftw_complex (
    )
    1> ]

    geht es hier doch, wenn dann wie?



  • std::transform wäre ein Kandidat:

    fftw_complex conv(std::complex<double> const& z)
    {
        return {real(z), imag(z)};
    }
    
    // …
    
    std::transform(InArray.begin(), InArray.end(), in, &conv);
    

    /edit: Blöd gelaufen, fftw_complex ist ein beschissener Typ. Ich würde bei memcopy bleiben, gegebenenfalls ein paar Compilerchecks davorsetzen.



  • Eine solche conv Funktion liefert mir den Fehler:

    h:\dev\cpp\svn\modelocksimulation\modelockingsimulation\include\fftw\QFFTW.h(58) : error C2090: Funktionsergebnis ist ein Array

    weil es ja wirklich ein double[2] Array ist. Und wenn ich den Pointer auf ein Array zurückgeben lasse:

    fftw_complex * StdComplexToFFTW(std::complex<double> const& z)
    {
    	fftw_complex * c = new fftw_complex;
    	c[0] = real(z);
    	c[1] = imag(z);
        return c;
    }
    

    dann schimpft std::transform:

    1> C:\Programme\Microsoft Visual Studio 8\VC\include\algorithm(709): Siehe Deklaration von 'std::transform'
    1>.\include\fftw\QFFTW.cpp(183) : error C2440: 'Initialisierung': 'double ' kann nicht in 'fftw_complex ()' konvertiert werden

    Lösung?



  • wäre der umgekehrte Weg gefährlich?

    memcpy(in,&InArray[0], m_size.x  * sizeof(complex<double>));
    

    das kompiliert nämlich.



  • Ich habe von einem Kollegen gesagt bekommen, das nicht alle vector Implementierungen wie ein C-Array gespeichert werden. Da würde es bei einem memcopy natürlich crashen.

    Auf welche Plattformen Implementierungen würde das denn heute noch zutreffen. Ich nutze derzeit VS2005 und unter Linux gcc 4.3.



  • Ich habe von einem Kollegen gesagt bekommen, das nicht alle vector Implementierungen wie ein C-Array gespeichert werden.

    Dann hat der Kollege vrmtl keine Ahnung...
    std::vector speichert alle Einträge an einem Stück... sieht stark vereinfacht etwa so aus:

    template <typename T>
    class vector
    {
     T * data;
     vector (size_t anz) : data (new T[anz])
      {}
    };
    

    Das, was nicht alles an einem Stück speichert heißt in der STL z.Bsp. deque oder (ganz einzeln) list .

    Deshalb sieht man auch oft so was:

    void bar(int *first, size_t anz);
    
    //------------------------------------------------------
    
    std::vector <int> bsp;
    for (int i = 0; i != 10; ++i)
    {
      bsp.push_back(i);
    }
    bar(&bsp[0], bsp.size());
    

    bb



  • Evtl. könnte noch ein recht alter Compiler so einen merkwürdigen vector haben. In der Fassung des Standards von 1998 war ein kontinuierliche Speicherung wie in einem C-array noch nicht gefordert.
    In der 2003er Fassung stand das dann aber drin.
    Standard 23.2.4 1



  • sagt folgendes:

    http://www.fftw.org/doc/Complex-numbers.html schrieb:

    Reportedly, the C++ standards committee has recently agreed to mandate that the storage format used for this type be binary-compatible with the C99 type, i.e. an array T[2] with consecutive real [0] and imaginary [1] parts. (See report WG21/N1388.) Although not part of the official standard as of this writing, the proposal stated that: “This solution has been tested with all current major implementations of the standard library and shown to be working.” To the extent that this is true, if you have a variable complex<double> *x, you can pass it directly to FFTW via reinterpret_cast<fftw_complex*>(x).

    Also:

    vector<complex<double> > & InArray;
    fftw_complex *in;
    
    std::copy(InArray.begin(), InArray.end(), reinterpret_cast<complex<double>*>(in));
    

    pospiech schrieb:

    wäre der umgekehrte Weg gefährlich?

    memcpy(in,&InArray[0], m_size.x  * sizeof(complex<double>));
    

    das kompiliert nämlich.

    Ja, der wäre gefährlich, wenn z.B. InArray.size() < m_size.x. Ich denke vorzuziehen wäre da etwas wie

    InArray.resize(m_size.x);
    std::complex<double>* first = std::reinterpret_cast<std::complex<double>*>(in);
    std::copy(first, first + m_size.x, InArray.begin());
    


  • pumuckl schrieb:

    Ja, der wäre gefährlich, wenn z.B. InArray.size() < m_size.x. Ich denke vorzuziehen wäre da etwas wie

    InArray.resize(m_size.x);
    std::complex<double>* first = std::reinterpret_cast<std::complex<double>*>(in);
    std::copy(first, first + m_size.x, InArray.begin());
    

    Das ist aber bei ungleichen Größen nicht minder gefährlich.



  • Tachyon schrieb:

    Das ist aber bei ungleichen Größen nicht minder gefährlich.

    Deshalb ja das resize() 🙂



  • pumuckl schrieb:

    Tachyon schrieb:

    Das ist aber bei ungleichen Größen nicht minder gefährlich.

    Deshalb ja das resize() 🙂

    Das geht natürlich auch bei memcpy

    Oder vielleicht lieber einen back_inserter benutzen. Dann ist die Größe relativ egal.

    std::copy(first, first + m_size.x, std::back_inserter(InArray));
    


  • Tachyon schrieb:

    Das geht natürlich auch bei memcpy

    Natürlich. Allerdings ist memcpy C und std::copy C++.
    fftw_complex scheint allerdings auch Bestandteil einer C-API zu sein, std::complex ist wieder C++. Ob man an einer Schnittstelle zwischen beidem jetzt lieber C-Funktionen oder C++-Funktionen benutzt ist denke ich größtenteils Geschmackssache. Kompiliert werden muss es aber so oder so in C++, daher würde ich zur C++-Funktion tendieren (genauso zu reinterpret_cast an Stelle eines simplen C-Casts.

    Oder vielleicht lieber einen back_inserter benutzen. Dann ist die Größe relativ egal.

    std::copy(first, first + m_size.x, std::back_inserter(InArray));
    

    Dann muss aber vorher der vector auch auf 0 resized werden, um hinterher nicht noch den alten Dreck im vector zu haben. Da kann mans dann lieber gleich richtig resizen, da man vorher die richtige Anzahl schon kennt.


Log in to reply