将C代码移植到C ++,将void *从malloc转换为所需的指针的问题 [英] Porting C code to C++, problem with casting void* from malloc to desired pointer
问题描述
我目前正在移植一些我写给C ++的C代码以供娱乐.我在用C进行的 malloc()
调用中苦苦挣扎,出于简单的原因, h
和 w
是常量,但后来与运行时交换了常数:
double(* g2)[h] [w] = malloc(h * w * sizeof(double));
在C语言中,这是 void *
的隐式转换,当然,这在C ++中不起作用.
我已经尝试使用 reinterpret_cast< double [h] [w]>
强制转换,但这仍然是无效的转换.
我想知道如何才能用C ++进行这项工作,因为这样可以节省很多工作?
作为替代方案,我可能会使用具有间接性的矩阵类:
struct Matrix:std :: vector< double>{无符号的matSize;std :: vector< double *>间接Matrix():matSize(0){}Matrix(unsigned n):matSize(n){调整大小(n * n);indirection.resize(n);for(unsigned i = 0; i< n; ++ i){indirection [i] =&(**)[i * n];}}双重&operator()(无符号i,无符号j){返回间接[i] [j];}const double&运算符()(无符号i,无符号j)const {返回间接[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] = ...;//或者g2 [y * w + x] = ...;
使用语法不方便访问元素,因此您可能希望将其包装在一个简单的类中.示例:
#include< iostream>#include< iterator>#include< vector>类arr2d {上市:arr2d(size_t h,size_t w):data_(h * w),w_(w){}内联double&运算符()(size_t y,size_t x){返回data_ [y * w_ + x];}内联双操作符()(size_t y,size_t x)const {返回data_ [y * w_ + x];}//获取指向行的指针内联double *运算符[](size_t y){返回& data_ [y * w_];}内联双精度const *运算符[](size_t y)const {返回& data_ [y * w_];}内联size_t width()const {return w_;}私人的:std :: vector< double>数据_;size_t w_;};int main(){arr2d g2(3,4);g2(2,3)= 3.14159;//替代访问:g2 [1] [2] = 1.23456;std :: cout<<g2 [2] [3]<<"\ n";double *行= g2 [2];std :: copy(row,row + g2.width(),std :: ostream_iterator< double>(std :: cout,,")));std :: cout<<"\ n";}
输出:
3.141590、0、0、3.14159,
非初始化版本可能如下:
class arr2d {上市:arr2d(size_t h,size_t w):data_(new double [w * h]),w_(w){}内联Double&operator()(size_t y,size_t x){return data_ [y * w_ + x];}内联双操作符()(size_t y,size_t x)const {return data_ [y * w_ + x];}内联double *运算符[](size_t y){return&_data_ [y * w_];}内联双精度const *运算符[](size_t y)const {return&_data_ [y * w_];}内联size_t width()const {return w_;}私人的:std :: unique_ptr< double []>数据_;size_t w_;};
但是请注意, std :: copy(row,row + g2.width(),std :: ostream_iterator< double>(std :: cout,``,``)));
从第一个示例开始将导致不确定的行为.
还请注意,此版本将删除复制构造函数和复制分配运算符.如果需要,必须自己实施.
非初始化版本的创建时间当然很难与任何初始化版本相提并论,但是对于访问时间,人们可能会认为查找表或您所谓的间接表会加快行速与一次性完成乘法和加法相比.
我的结果: 似乎有所不同.对于4096x4096矩阵,查找版本速度更快,但是对于两个较小的矩阵,原始版本的查找速度更快.您需要比较接近将要使用的大小,并检查不同的编译器.有时我会与赢家"完全相反更改编译器时. 由于您不介意从 以下是Philipp-P(OP:s)自己针对不同2D阵列实现的测量结果: 相同版本的5点模板代码的结果: I am currently porting some C code I wrote to C++ for fun. I am struggling with a In C, this is an implicit conversion of a I already tried casting this with I was wondering, how can I make this work in C++ since this would save me a lot of work? As an alternative I'll probably use a matrix class with indirection:
Porting involves more than just making it work, line by line, so: C: C++: Using that syntax is inconvenient for accessing elements so you might want to wrap it inside a simple class. Example: Output: A non-initializing version could look like: But note that the Also note that this version will delete the copy constructor and copy assignment operator. You'll have to implement them yourself if you need them. The creation time for the non-initializing version is of course hard to beat with any initializing version, but for access times, one might think that a lookup table, or indirection as you call it, for the rows would speed up things compared to doing the multiplication and addition in one go. My results: It seems to vary. The lookup version is faster for the 4096x4096 matrix but the naive version is faster for the two smaller ones. You need to compare using sizes close to what you'll be using and also check with different compilers. I sometimes get completely opposite "winners" when changing compiler. Since you don't mind inheriting from Here are Philipp-P's (OP:s) own measurements for the different 2D-array implementations: Results for 5-point stencil code for the same versions: 这篇关于将C代码移植到C ++,将void *从malloc转换为所需的指针的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! 8x8
http://quick-bench.com/f8zcnU9P8oKwMUwLRXYKZnLtcLM 1024x1024
http://quick-bench.com/0B2rQeUkl-WoqGeG-iS1hdP4ah8 4096x4096
http://quick-bench.com/c_pGFmB2C9_B3r3aRl7cDK6BlxU> std :: vector
继承或为查找表保留额外的数据,因此可以选择.似乎比其他版本略胜一筹.
class arr2d:受保护的std :: vector< double *>{上市:使用std :: vector< double *> :: operator [];//行"来自基类的访问器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];}内联size_t width()const {return w_;}内联size_t height()const {return h_;}私人的:std :: unique_ptr< double []>数据_;size_t w_,h_;};
8x8
http://quick-bench.com/vMS6a9F_KrUf97acWltjV5CFhLY 1024x1024
http://quick-bench.com/A8a2UKyHaiGMCrf3uranwOCwmkA 4096x4096
http://quick-bench.com/XmYQc0kAUWU23V3Go0Lucioi_Rg 8x8
http://quick-bench.com/in_ZQTbbhur0I4mu-NIquT4c0ew 1024x1024
http://quick-bench.com/tULLumHZeCmC0HUSfED2K4nEGG8 4096x4096
http://quick-bench.com/_MRNRZ03Favx91-5IXnxGNpRNwQ malloc()
call I make in C, with h
and w
being constants for simplicity reasons, but later exchanged with runtime constants:double (*g2)[h][w] = malloc(h * w * sizeof(double));
void*
, and this of course doesn't fly with C++.reinterpret_cast<double[h][w]>
, but this is still an invalid cast.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];
}
};
double (*g2)[h][w] = malloc(h * w * sizeof(double));
...
g2[y][x] = ...;
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, ", "));
from the first example would lead to undefined behaviour.
8x8
http://quick-bench.com/f8zcnU9P8oKwMUwLRXYKZnLtcLM
1024x1024
http://quick-bench.com/0B2rQeUkl-WoqGeG-iS1hdP4ah8
4096x4096
http://quick-bench.com/c_pGFmB2C9_B3r3aRl7cDK6BlxUstd::vector
or keeping extra data for a lookup-table, this could be an option. It seems to outperform the other versions slightly.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_;
};
8x8
http://quick-bench.com/vMS6a9F_KrUf97acWltjV5CFhLY
1024x1024
http://quick-bench.com/A8a2UKyHaiGMCrf3uranwOCwmkA
4096x4096
http://quick-bench.com/XmYQc0kAUWU23V3Go0Lucioi_Rg
8x8
http://quick-bench.com/in_ZQTbbhur0I4mu-NIquT4c0ew
1024x1024
http://quick-bench.com/tULLumHZeCmC0HUSfED2K4nEGG8
4096x4096
http://quick-bench.com/_MRNRZ03Favx91-5IXnxGNpRNwQ