std::copy() 与 memcpy() 与 std::vectors 和 fftw_malloc

问题描述 投票:0回答:1

我知道在处理

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()
来代替吗?

c++ c++11 stdvector memcpy
1个回答
2
投票

背景:标准将其从

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;
};
© www.soinside.com 2019 - 2024. All rights reserved.