我目前正在移植一些我写给C++的C代码以供娱乐。我在用C进行的malloc()调用中苦苦挣扎,由于简单起见,hw是常量,但后来与运行时常量交换了:

double (*g2)[h][w] = malloc(h * w * sizeof(double));

在C语言中,这是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];
    }
};

最佳答案

移植不仅涉及逐行工作,因此:
C:

double (*g2)[h][w] = malloc(h * w * sizeof(double));
...
g2[y][x] = ...;
C++:
std::vector<double> g2(h*w);
...
g2[y+x*h] = ...; // or
g2[y*w+x] = ...;
使用该语法不方便访问元素,因此您可能希望将其包装在一个简单的类中。例子:
#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";
}
输出:
3.14159
0, 0, 0, 3.14159,
非初始化版本可能如下所示:
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_;
};
但是请注意std::copy(row, row + g2.width(), std::ostream_iterator<double>(std::cout, ", "));从第一个示例开始,将导致不确定的行为。
另请注意,此版本将删除复制构造函数和复制分配运算符。如果需要,则必须自己实现。
非初始化版本的创建时间当然很难与任何初始化版本相提并论,但是对于访问时间,人们可能会认为查找表或您所谓的间接表,因为与之相比,行会加快处理速度一路相乘。
我的结果: 8x8 http://quick-bench.com/f8zcnU9P8oKwMUwLRXYKZnLtcLM1024x1024 http://quick-bench.com/0B2rQeUkl-WoqGeG-iS1hdP4ah84096x4096 http://quick-bench.com/c_pGFmB2C9_B3r3aRl7cDK6BlxU
它似乎有所不同。对于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_;
};
以下是Philipp-P(OP:s)自己针对不同2D阵列实现的测量结果: 8x8 http://quick-bench.com/vMS6a9F_KrUf97acWltjV5CFhLY1024x1024 http://quick-bench.com/A8a2UKyHaiGMCrf3uranwOCwmkA4096x4096 http://quick-bench.com/XmYQc0kAUWU23V3Go0Lucioi_Rg
相同版本的5点模板代码的结果: 8x8 http://quick-bench.com/in_ZQTbbhur0I4mu-NIquT4c0ew1024x1024 http://quick-bench.com/tULLumHZeCmC0HUSfED2K4nEGG84096x4096 http://quick-bench.com/_MRNRZ03Favx91-5IXnxGNpRNwQ

09-06 12:22