对于二维矩阵,它在 C++11 中的函数是否与 C11 中的函数类似
Is it a similar function in C++11 as in C11 for the twodimensional matrix?
我注意到在 gcc C11 中您可以将任何矩阵传递给函数fn(int row, int col, int array[row][col])
。如何将我在 C11 中的以下放置(链接到另一个堆栈溢出答案(程序转换为 C++11 中的程序?
C - 在函数中分配矩阵
如您所见,我可以在 C11 中将静态和动态分配数组传递给函数。在 C++11 中可能吗?
我基于不同的堆栈溢出答案制作了一个示例程序,但是所有函数都适用于 array1,而它们都不适用于 array2,其中 double array1[ROW][COL] = { { } }
和 auto array2 = new double[ROW][COL]()
?
如何像在 C11 fn(int row, int col, int array[row][col])
中那样为两个数组创建一个函数?
#include <iostream>
#include <utility>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
using namespace std;
const int ROW=2;
const int COL=2;
template <size_t row, size_t col>
void process_2d_array_template(double (&array)[row][col])
{
cout << __func__ << endl;
for (size_t i = 0; i < row; ++i)
{
cout << i << ": ";
for (size_t j = 0; j < col; ++j)
cout << array[i][j] << 't';
cout << endl;
}
}
void process_2d_array_pointer(double (*array)[ROW][COL])
{
cout << __func__ << endl;
for (size_t i = 0; i < ROW; ++i)
{
cout << i << ": ";
for (size_t j = 0; j < COL; ++j)
cout << (*array)[i][j] << 't';
cout << endl;
}
}
// int array[][10] is just fancy notation for the same thing
void process_2d_array(double (*array)[COL], size_t row)
{
cout << __func__ << endl;
for (size_t i = 0; i < row; ++i)
{
cout << i << ": ";
for (size_t j = 0; j < COL; ++j)
cout << array[i][j] << 't';
cout << endl;
}
}
// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(double **array, size_t row, size_t col)
{
cout << __func__ << endl;
for (size_t i = 0; i < row; ++i)
{
cout << i << ": ";
for (size_t j = 0; j < col; ++j)
cout << array[i][j] << 't';
cout << endl;
}
}
int main()
{
double array1[ROW][COL] = { { } };
process_2d_array_template(array1);
process_2d_array_pointer(&array1); // <-- notice the unusual usage of addressof (&) operator on an array
process_2d_array(array1, ROW);
// works since a's first dimension decays into a pointer thereby becoming int (*)[COL]
double *b[ROW]; // surrogate
for (size_t i = 0; i < ROW; ++i)
{
b[i] = array1[i];
}
process_pointer_2_pointer(b, ROW, COL);
// allocate (with initialization by parentheses () )
auto array2 = new double[ROW][COL]();
// pollute the memory
array2[0][0] = 2;
array2[1][0] = 3;
array2[0][1] = 4;
array2[1][1] = 5;
// show the memory is initialized
for(int r = 0; r < ROW; r++)
{
for(int c = 0; c < COL; c++)
cout << array2[r][c] << " ";
cout << endl;
}
//process_2d_array_pointer(array2);
//process_pointer_2_pointer(array2,2,2);
int info;
cout << abi::__cxa_demangle(typeid(array1).name(),0,0,&info) << endl;
cout << abi::__cxa_demangle(typeid(array2).name(),0,0,&info) << endl;
return 0;
}
您在 C11 中使用的功能是在 C99 中引入的,专门设计用于允许高效轻松地处理多维数组。
虽然C++在(多维(数组方面与 C 共享基本语法,但数组类型在C++中的能力要小得多:C++数组类型的大小需要是编译时常量。以下是一些示例:
void foo(int a, int b) {
int foo[2][3]; //legal C++, 2 and 3 are constant
int bar[a][3]; //Not C++, proposed for C++17: first dimension of an array may be variable
int baz[a][b]; //Not C++, legal in C99
int (*fooPtr)[2][3]; //legal C++
int (*barPtr)[a][3]; //Not C++, legal in C99
int (*bazPtr)[a][b]; //Not C++, legal in C99
typedef int (*fooType)[2][3]; //legal C++
typedef int (*barType)[a][3]; //Not C++, legal in C99
typedef int (*bazType)[a][b]; //Not C++, legal in C99
int (*dynamicFoo)[3] = new int[2][3]; //legal C++
int (*dynamicBar)[3] = new int[a][3]; //legal C++
int (*dynamicBar)[b] = new int[a][b]; //Not C++
}
如您所见,在 C 语言中,动态大小数组的几乎所有可能的事情在C++中都是不可能的。即使是为下一个C++标准提出的VLA扩展也没有多大帮助:它仅限于数组的第一维。
在C++中,您必须使用std::vector<>
来实现 C99 可变长度数组可以实现的目标。所有后果:
std::vector<std::vector<> >
中的数据在内存中不是连续的。您的缓存可能不喜欢这样。std::vector<std::vector<> >
不能保证所有线性阵列具有相同的长度。这可能有用,也可能很痛苦,具体取决于您的用例。如果您有对
std::vector<std::vector<> >
中的元素的迭代器,则无法将其前进到下一行中的相应元素。
VLA。它被提议用于 C++17,但还有很多工作要做,因为它对类型系统来说是一个相当大的变化,无论如何,使用 C 样式数组在C++都是不受欢迎的。
如您所发现的,当编译时大小已知时,您可以使用模板。如果在编译时不知道大小,那么最好的办法是使用包装在类中的一维vector
以您想要访问它的方式访问它。
当然,vectors
的vector
也是可能的;它描述了一个交错数组。您是否更喜欢单个大内存块取决于各种因素(编码的复杂性、运行时速度/内存使用注意事项等(。
- 函数是否可以访问传递给main()的参数
- 根据某个函数是否存在启用模板
- 无论如何,我可以确定构造函数是否存在吗?
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 如何检查函数是否在LLVM Instrumentation pass的ModulePass的系统头文件中定义?
- 如果 C 函数仍然可以间接执行(通过回调函数),那么将它声明为静态函数是否是一种不好的做法?
- 在对象构造期间,将指向尚未构造的子对象的指针传递给另一个子对象的构造函数是否危险?
- 某些 boost::asio 异步函数是否将处理程序连接到操作,以便处理程序被触发一次?
- 调用 erase() 函数是否也会在擦除元素之前更改迭代器值?
- 由并发无序映射查找线程调用的函数是否安全?
- 使用静态成员函数而不是普通函数是否有任何开销?
- 从其存储的回调中删除 std::函数是否安全
- 析构函数是否会自动调用 delete[] C++?
- 构造函数是否有一种现代C++方法来了解其'container'类?
- 循环中本地对象的析构函数是否保证在下一次迭代之前被调用?
- 移动构造函数是否C++过时?
- 在 c++ 中将对象设置为等于同一类的构造函数是否有效?
- 此函数是否会在C++中创建内存泄漏?
- 具有默认值的单个参数构造函数是否与默认构造函数相同?
- 如何检测构造函数是否与抛出的析构函数无关