我知道在处理
std::vector
时,最好使用 std::copy()
,但是我想知道如何将 fftw_malloc
数组复制到 std::vector
中?我应该使用 std::copy()
还是 memcpy()
?
示例代码:
static const int nx = 8;
static const int ny = 8;
static const int nyk = ny/2 + 1;
static const int Mx = 3*nx/2, My= 3*ny/2;
double M[2] = {Mx,My};
fftw_complex *array1;
array1= (fftw_complex*) fftw_malloc(nx*nyk* sizeof(fftw_complex));
memset(array1, 42, nx*nyk* sizeof(fftw_complex));
std::vector<std::complex<double>> array2(Mx*My,0.0);
std::copy( array1, array1+(nx*nyk) , array2); //std::copy( src, src + size, dest );
我正在尝试将
array1
复制到 array2
,其中 array2 > array1
,然后想使用 std::vector
运算符附加值,依此类推。
这实际上不起作用,我不确定我的
vector
语法是否已关闭,或者 std::copy()
不是正确的方法。我应该使用 memcpy()
来代替吗?
背景:标准将其从
reinterpret_cast<double*>
定义为 std::complex<double>*
,反之亦然。 std::complex<double>
的内存布局保证是内存中两个相邻 double
的内存布局。在内部,它可能类似于以下任何一个:
template<class T>
struct complex1 {
T m_real;
T m_img;
};
//---
template<class T>
struct complex2 {
T m_data[2];
};
//---
template<class T> struct complex3;
template<>
struct complex3<double> {
double _Complex m_data; // The C complex type
};
std:complex<T>
是为数不多的(也许是唯一?)类之一,您可以保证可以通过reinterpret_cast
指向它的指针并像通过指向另一种类型的指针一样来回查看它。
但是,使用这些不同的类型并不好,并且会用
reinterpret_cast
使代码变得混乱,所以我首先编写一个包装器,我们称之为 ComplexArray
,围绕由 fftw_malloc
返回的原始指针 - 而且我会使用 fftw_alloc_complex
而不是更通用的 fftw_malloc
。包装器应该为您作为 C++ 程序员提供处理数据的可能性,以便它可以与 C++ 标准库中的算法一起使用。
我仍然会使用
fftw
分配函数,而不是直接使用 std::vector<std::complex<double>>
(这完全没问题),因为它们 ”保证返回的指针遵守 FFTW 中任何算法施加的任何特殊对齐限制(例如用于 SIMD 加速)”.
通过为该包装器提供迭代器支持,将数据复制到
std::vector<std::complex<double>>
变得与使用任何 C++ 容器一样简单。您甚至可以直接从包装器的迭代器创建 vector
。
目标是可以像这样编写
main
函数:
int main() {
static const int nx = 8;
static const int ny = 8;
static const int nyk = ny / 2 + 1;
static const int Mx = 3 * nx / 2, My = 3 * ny / 2;
ComplexArray array1(nx * nyk); // the new C++ container
// no more memset(..., 42, ...), use real C++ std::complex<double>s:
array1.fill(std::complex<double>{1.4260258159703532e-105,
1.4260258159703532e-105});
// create a vector from your ComplexArray
std::vector<std::complex<double>> array2(array1.begin(), array1.end());
}
ComplexArray
的示例实现可能如下所示,并且在您使用std::vector<std::complex<double>>
时所需的大多数情况下可以替代fftw
,因此您甚至可能不需要将其复制到vector
,您可以如果需要,可以添加复制并从迭代器和其他有用的东西创建它。这是一个开始:
#include <algorithm>
#include <complex>
#include <iterator>
#include <memory>
class ComplexArray {
public:
using value_type = std::complex<double>;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = value_type*;
using const_iterator = const value_type*;
using reverse_iterator = std::reverse_iterator<iterator>;
using reverse_const_iterator = std::reverse_iterator<const_iterator>;
ComplexArray() = default;
ComplexArray(std::size_t size) : m_data(fftw_alloc_complex(size)) {}
ComplexArray(ComplexArray&&) = default;
ComplexArray& operator=(ComplexArray&&) = default;
// misc ...
std::size_t size() const { return m_size; }
void fill(std::complex<double> val) { std::fill(begin(), end(), val); }
// access
const_pointer data() const {
return reinterpret_cast<const_pointer>(m_data.get());
}
pointer data() { return reinterpret_cast<pointer>(m_data.get()); }
const_reference operator[](std::size_t idx) const { return data()[idx]; }
reference operator[](std::size_t idx) { return data()[idx]; }
// functions to provide fftw functions direct access to the data
const fftw_complex* fftw_data() const { return m_data.get(); }
fftw_complex* fftw_data() { return m_data.get(); }
// iterators ...
const_iterator cbegin() const { return data(); }
const_iterator cend() const { return data() + m_size * sizeof(value_type); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
iterator begin() { return data(); }
iterator end() { return data() + m_size * sizeof(value_type); }
// reverse iterators ...
reverse_const_iterator crbegin() const {
return reverse_const_iterator(cend());
}
reverse_const_iterator crend() const {
return reverse_const_iterator(cbegin());
}
reverse_const_iterator rbegin() const { return crbegin(); }
reverse_const_iterator rend() const { return crend(); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
private:
struct fftw_freer {
void operator()(fftw_complex* cplx) const noexcept { fftw_free(cplx); }
};
std::unique_ptr<fftw_complex, fftw_freer> m_data;
std::size_t m_size = 0;
};