将 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> {
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] = ...;
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
C++除非必要,否则不建议手动分配内存。让标准库和模板为您完成工作。
它们非常有用,如果您想进入C++,它们非常适合学习!通过这种方式,您可以节省大量时间并编写一些更好的代码。
例如,此数据类型的用途是什么?如果它适合您的使用,您可以改为考虑使用std::array
创建一个 2D 数组:
std::array<std::array<double, w>, h>
如果需要定期调整数组大小,可以改用std::vector
。它实际上具有与阵列相同的性能,因为这就是它的全部功能。您可以根据需要reserve()
或resize()
,push_back
使用1.5倍的递增方案,并且擅长其工作。
编辑:由于大小已知,数组在这里可能更好。从评论中获取建议。
我建议你使用std::vector。如果你想要 2D 数组语法,只需包装它。
#include <iostream>
#include <vector>
class Array2D {
std::vector<double> _v;
size_t _width;
size_t _height;
public:
Array2D(size_t height, size_t width, double initVal = 0.0)
: _v(width * height, initVal),
_width(width),
_height(height)
{}
double* operator[](size_t y) {
return _v.data() + y * _width;
}
};
int main(int, char**) {
size_t rows = 5;
size_t cols = 3;
Array2D a(rows, cols, 0.2);
for (size_t i = 0; i < cols; ++i)
a[4][i] = -0.1 * i;
std::cout << a[4][2] << std::endl; //-0.2
return 0;
}
你可以这样做,这应该在C和C++中都有效:
double *g2 = (double*) malloc(h * w * sizeof(double));
然而,正如其他人所说,这不是一般C++处理这个问题的方法。例如,您应该改用std::vector
:
#include <vector>
std::vector<double> g2(h * w);
在这两种情况下,您最终都会在单个连续内存块中获得动态分配的 2Ddouble
数组。因此,您需要使用g2[(row*w)+col]
语法来访问各个元素,其中0 <= row < h
和0 <= col < w
.
- 如果没有malloc,链表实现将失败
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 malloc 转换为新的正确方法
- 将 C 代码移植到C++,将 void* 从 malloc 转换为所需指针的问题
- 将 malloc 转换为新的或 std::vector
- x = malloc(n * sizeof (int));无法将 void 转换为 int
- 数据类型(从 malloc 返回)是如何转换的?
- 如何使用malloc从一维数组转换为二维数组
- 如何使用 malloc() 将 C 语句转换为 C++
- 为什么 new 不需要强制转换为指针,即使 malloc 需要它?
- 在汇编中使用malloc分配的内存-希望在c++中将其转换为三维数组
- 避免c++中的malloc:从' void* '到' uv_loop_t* '的无效转换
- 将static_cast<字符 *>malloc/free/free转换为新的/删除
- 将malloc转换为新的c++ for结构体
- 类型转换malloc c++
- 将 malloc 转换为新的