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 werdenLö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.