如何在 Visual Studio C++ 11 中运行时定义二维数组?

How to define a two dimensional array during run time in Visual Studio C++ 11?

本文关键字:运行时 定义 二维数组 C++ Visual Studio      更新时间:2023-10-16

我正在尝试使用Visual Studio 2015 vc14 x64编译器在Windows上编译ORBSLAM2。该项目最初是为GNU GCC开发的。我现在有以下问题:

// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}

我在编译时收到此错误:

C2131 表达式的计算结果未达到常数

。在以下代码行上:

const size_t N = vDescriptors.size();

随后,二维数组定义也失败了(float Distances[N][N];(。

在视觉C++中解决此问题的最佳方法是什么?

更新:这是完整的函数代码:

void MapPoint::ComputeDistinctiveDescriptors() {
// Retrieve all observed descriptors
vector<cv::Mat> vDescriptors;
map<KeyFrame*,size_t> observations;
{
unique_lock<mutex> lock1(mMutexFeatures);
if(mbBad)
return;
observations=mObservations;
}
if(observations.empty())
return;
vDescriptors.reserve(observations.size());
for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) {
KeyFrame* pKF = mit->first;
if(!pKF->isBad())
vDescriptors.push_back(pKF->mDescriptors.row(mit->second));
}
if(vDescriptors.empty())
return;
// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}
// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances[i], aDistances[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}
{
unique_lock<mutex> lock(mMutexFeatures);
mDescriptor = vDescriptors[BestIdx].clone();
}
}

你的问题

您尝试在堆栈上创建一个 2D 数组(这不是标准C++,即使它可能适用于某些编译器(。为此,需要在编译时知道大小,这不是这种情况,因为您在可能不是constexpr的对象上调用size()

快速修复

开箱即用的快速修复方法是

通过
float** aDistances = new float[N][N];

删除可以在如下所示的函数中完成

template <typename T>
void delete2DArray(T** ptr, size_t NumRows)
{
for (size_t i = 0; i < NumRows; i++)
{
delete[] ptr[i];
}
delete[] ptr;
}

修复

您必须使用动态内存分配。为此,您可以通过在 std::vector 周围添加一个包装类来尝试以下方法(这应该是可能的,因为您说范围非常易于管理(

template <typename T>
class Array2D
{
public:
Array2D(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), array2d(rows * columns)
{}
T& operator()(size_t row, size_t column)
{
return array2d[row * columns + column]; 
}
const T& operator()(size_t row, size_t column) const
{
return array2d[row * columns + column];
}
T* getRow(size_t row)
{
return &array2d[row * columns];
}

private:
size_t rows;
size_t columns;
std::vector<T> array2d;
};

然后你必须像这样修改你的代码:

// Compute distances between them
const size_t N = vDescriptors.size();
Array2D<float> aDistances(N,N);
for (size_t i = 0; i < N; i++) {
aDistances(i,i) = 0;
for (size_t j = i + 1; j < N; j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i], vDescriptors[j]);
aDistances(i,j) = distij ;
aDistances(j,i) = distij ;
}
}

如您所见,访问元素的语法略有变化 [x][y] -> (x,y(。

编辑

由于OP修改了问题,我注意到第二次使用Distances,这也需要注意。为此,您必须将getColumn方法(见上文(添加到Array2D类中。比你进一步必须修改

// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances.getRow()[i], aDistances.getRow()[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}

注意:我不完全确定我是否做对了 - 也许你必须得到一个 列而不是行(为时已晚,无法直接思考(。如果是这种情况,您还应该更改 Array2D 类的内存布局,即在底层 1D 矢量中以不同的方式对元素进行排序。