Как определить двумерный массив во время выполнения в Visual Studio C ++ 11? - PullRequest
0 голосов
/ 05 сентября 2018

Я пытаюсь скомпилировать ORBSLAM2 в Windows с компилятором Visual Studio 2015 vc14 x64. Проект изначально разрабатывался для 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];).

Какой лучший способ решить эту проблему в Visual-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();
    }
}

1 Ответ

0 голосов
/ 05 сентября 2018

Ваша проблема

Вы пытались создать двумерный массив в стеке (это не является стандартным C++, хотя это может работать на некоторых компиляторах). Для этого необходимо знать размер во время компиляции, а это не так, когда вы вызываете size() для объекта, который, вероятно, не является constexpr.

БЫСТРЫЙ ИСПРАВЛЕНИЕ

Быстрое исправление, которое работает «из коробки», состоит в том, чтобы просто выделить память в куче ( не забудьте позже удалить массив ), выполнив

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;
}

FIX

Вам придется использовать динамическое распределение памяти. Для этого вы можете попробовать следующий подход, добавив класс-оболочку вокруг 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).

EDIT

Поскольку ОП изменил вопрос, я заметил, что 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-векторе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...