将C代码移植到C ++,将void *从malloc转换为所需指针的问题

Phi*_*p-P 4 c++ pointers type-conversion void-pointers

我目前正在移植一些我写给C ++的C代码以供娱乐。我有挣扎malloc()呼叫我在做C,与hw是为简单起见常数,但后来随着运行时间的常数交换:

double (*g2)[h][w] = malloc(h * w * sizeof(double));
Run Code Online (Sandbox Code Playgroud)

在C语言中,这是A的隐式转换void*,而C ++当然不会实现。

我已经尝试使用进行强制转换reinterpret_cast<double[h][w]>,但这仍然是无效的强制转换。

我想知道如何才能用C ++进行这项工作,因为这可以节省很多工作?

作为替代,我可能会使用带间接的矩阵类:

struct Matrix : std::vector<double> {
    unsigned matSize;
    std::vector<double*> indirection;
    Matrix() : matSize(0) {}
    Matrix(unsigned n) : matSize(n) {
        resize(n*n);
        indirection.resize(n);
        for(unsigned i = 0; i < n; ++i) {
            indirection[i] = &(*this)[i*n];
        }
    }
    double& operator()(unsigned i, unsigned j) {
        return indirection[i][j];
    }
    const double& operator()(unsigned i, unsigned j) const {
        return indirection[i][j];
    }
};
Run Code Online (Sandbox Code Playgroud)

Ted*_*gmo 7

移植不仅需要逐行地使其工作,所以:

C:

double (*g2)[h][w] = malloc(h * w * sizeof(double));
...
g2[y][x] = ...;
Run Code Online (Sandbox Code Playgroud)

C ++:

std::vector<double> g2(h*w);
...
g2[y+x*h] = ...; // or
g2[y*w+x] = ...;
Run Code Online (Sandbox Code Playgroud)

使用该语法访问元素非常方便,因此您可能希望将其包装在一个简单的类中。例:

#include <iostream>
#include <iterator>
#include <vector>

class arr2d {
public:
    arr2d(size_t h, size_t w) : data_(h * w), w_(w) {}

    inline double& operator()(size_t y, size_t x) { 
        return data_[y * w_ + x];
    }
    inline double operator()(size_t y, size_t x) const {
        return data_[y * w_ + x];
    }

    // getting pointer to a row
    inline double* operator[](size_t y) {
        return &data_[y * w_];
    }
    inline double const* operator[](size_t y) const {
        return &data_[y * w_];
    }

    inline size_t width() const { return w_; }

private:
    std::vector<double> data_;
    size_t w_;
};

int main() {
    arr2d g2(3, 4);

    g2(2, 3) = 3.14159;
    // alternative access:
    g2[1][2] = 1.23456;

    std::cout << g2[2][3] << "\n";

    double* row = g2[2];
    std::copy(row, row + g2.width(), std::ostream_iterator<double>(std::cout, ", "));
    std::cout << "\n";
}
Run Code Online (Sandbox Code Playgroud)

输出:

3.14159
0, 0, 0, 3.14159,
Run Code Online (Sandbox Code Playgroud)

非初始化版本可能如下所示:

class arr2d {
public:
    arr2d(size_t h, size_t w) : data_(new double[w * h]), w_(w) {}

    inline double& operator()(size_t y, size_t x) { return data_[y * w_ + x]; }
    inline double operator()(size_t y, size_t x) const { return data_[y * w_ + x]; }

    inline double* operator[](size_t y) { return &data_[y * w_]; }
    inline double const* operator[](size_t y) const { return &data_[y * w_]; }

    inline size_t width() const { return w_; }

private:
    std::unique_ptr<double[]> data_;
    size_t w_;
};
Run Code Online (Sandbox Code Playgroud)

但是请注意,
std::copy(row, row + g2.width(), std::ostream_iterator<double>(std::cout, ", "));
第一个示例中的会导致未定义的行为。

另请注意,此版本将删除复制构造函数和复制分配运算符。如果需要,则必须自己实施。

非初始化版本的创建时间当然很难与任何初始化版本相提并论,但是对于访问时间,人们可能会认为查找表或您所谓的间接表,因为与之相比,行会加快处理速度一路相乘和加法。

我的结果:
8x8 http : //quick-bench.com/f8zcnU9P8oKwMUwLRXYKZnLtcLM
1024x1024 http://quick-bench.com/0B2rQeUkl-WoqGeG-iS1hdP4ah8
4096x4096 http://quick-bench.com/c_pGFmB2C9_B3r3aRl7

它似乎有所不同。对于4096x4096矩阵,查找版本速度更快,但是对于两个较小的矩阵,原始版本的查找速度更快。您需要比较使用的大小接近将要使用的大小,并还要检查不同的编译器。更改编译器时,有时我会遇到完全相反的“赢家”。

由于您不介意从std::vector查询表继承或保留额外的数据,因此可以选择。它似乎略胜于其他版本。

class arr2d : protected std::vector<double*> {
public:
    using std::vector<double*>::operator[]; // "row" accessor from base class

    arr2d(size_t h, size_t w) :
        std::vector<double*>(h), 
        data_(new double[w * h]), 
        w_(w),
        h_(h)
    {
        for(size_t y = 0; y < h; ++y)
            (*this)[y] = &data_[y * w];
    }

    inline size_t width() const { return w_; }
    inline size_t height() const { return h_; }

private:
    std::unique_ptr<double[]> data_;
    size_t w_, h_;
};
Run Code Online (Sandbox Code Playgroud)

以下是Philipp-P(OP:s)自己针对不同2D阵列实现的测量结果:

8x8 http://quick-bench.com/vMS6a9F_KrUf97acWltjV5CFhLY
1024x1024 http://quick-bench.com/A8a2UKyHaiGMCrf3uranwOCwmkA
4096x4096 http://quick-bench.com/XmYQc0kAUWU23V3Go0Lucioi_Rg

相同版本的5点模板代码的结果:
8x8 http : //quick-bench.com/in_ZQTbbhur0I4mu-NIquT4c0ew
1024x1024 http://quick-bench.com/tULLumHZeCmC0HUSfED2K4nEGG8
4096x4096 http://quick-bench.com/_MRNRZ03Favx91-5QIXx

  • @ Philipp-P这是一个连续的内存块,我怀疑它的性能是否与您的C版本的g2不同。它执行相同的查找。 (3认同)
  • @ Philipp-P好,为此添加了示例。 (3认同)