首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将C代码移植到C++,在将void*从malloc转换到所需指针时出现问题

将C代码移植到C++,在将void*从malloc转换到所需指针时出现问题
EN

Stack Overflow用户
提问于 2019-09-26 17:43:19
回答 4查看 354关注 0票数 4

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

代码语言:javascript
复制
double (*g2)[h][w] = malloc(h * w * sizeof(double));

在C语言中,这是一个void*的隐式转换,当然,这并不适用于C++。

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

我想知道,我如何在C++中完成这个工作,因为这将为我节省大量的工作。

作为另一种选择,我可能会使用一个间接的矩阵类:

代码语言:javascript
复制
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];
    }
};
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-09-26 17:51:23

移植不仅仅是让它工作,一行行,所以:

C:

代码语言:javascript
复制
double (*g2)[h][w] = malloc(h * w * sizeof(double));
...
g2[y][x] = ...;

C++:

代码语言:javascript
复制
std::vector<double> g2(h*w);
...
g2[y+x*h] = ...; // or
g2[y*w+x] = ...;

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

代码语言:javascript
复制
#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";
}

输出:

代码语言:javascript
复制
3.14159
0, 0, 0, 3.14159,

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

代码语言:javascript
复制
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/f8zcnU9P8oKwMUwLRXYKZnLtcLM

1024x1024 http://quick-bench.com/0B2rQeUkl-WoqGeG-iS1hdP4ah8

4096x4096 http://quick-bench.com/c_pGFmB2C9_B3r3aRl7cDK6BlxU

似乎各不相同。对于4096x4096矩阵,查找版本更快,而对于两个较小的矩阵,朴素版本更快。您需要将使用的大小与将要使用的大小进行比较,并与不同的编译器进行检查。有时,当我改变编译器时,我会得到完全相反的“赢家”。

因为您不介意从std::vector继承或为查找表保留额外的数据,所以这可能是一个选项。它的表现似乎略好于其他版本。

代码语言:javascript
复制
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_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-5IXnxGNpRNwQ

票数 7
EN

Stack Overflow用户

发布于 2019-09-26 17:51:52

在C++中,除非有必要,否则不建议手动分配内存。让标准库和模板为您工作。

如果您想进入C++,它们可能非常有用,学习起来也很棒!这样可以节省很多时间,并编写一些更好的代码。

例如,此数据类型用于什么?如果它适合您的使用,您可以考虑使用std::array创建2D数组。

std::array<std::array<double, w>, h>

如果需要定期调整数组的大小,则可以使用std::vector。它实际上具有与数组相同的性能,因为这就是它在引擎罩下的全部性能。您可以在必要时使用reserve()resize()push_back使用1.5倍的增长方案,并且擅长其工作。

编辑:由于已知的大小,数组在这里可能会更好。从评论中得到建议。

票数 3
EN

Stack Overflow用户

发布于 2019-09-26 18:10:07

您可以这样做,这在C和C++中都可以使用:

代码语言:javascript
复制
double *g2 = (double*) malloc(h * w * sizeof(double));

尽管,正如其他人所指出的,在C++中,这并不是解决这个问题的方法。例如,您应该使用std::vector来代替:

代码语言:javascript
复制
#include <vector>
std::vector<double> g2(h * w);

在这两种情况下,您都会在一个连续的内存块中得到一个动态分配的2D double数组。因此,您需要使用g2[(row*w)+col]语法来访问各个元素,其中0 <= row < h0 <= col < w

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58122125

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档