Использование глобального объекта C ++ из приложения C вылетает - PullRequest
3 голосов
/ 06 марта 2011

Это мой первый пост, я новичок в этом сайте, но я уже некоторое время тащусь вокруг. У меня хорошее знание C и очень ограниченное знание C ++. Похоже. Я на Windows (XPx64), VS2008.

Я пытаюсь обернуть библиотеку C ++, kdtree2 , чтобы я мог использовать ее из C. Основные проблемы связаны с доступом к классам kdtree2 и kdtree2_result_vector. Поскольку авторы ftp-сервера не отвечают, я загрузил копию исходного дистрибутива kdtree2 src

Просто небольшая информация о kd-дереве (форма двоичного дерева), «данные» - это координаты в n-мерном декартовом пространстве и индекс. Для чего они используются - это поиск ближайшего соседа, поэтому после Построив дерево (которое не будет изменено), можно запросить дерево для различных типов nn-поисков.Результаты в этом случае возвращаются в векторном объекте структур (c-подобных структур).

struct kdtree2_result {
  // 
  // the search routines return a (wrapped) vector
  // of these. 
  //
public:
  float dis;  // its square Euclidean distance
  int idx;    // which neighbor was found
}; 

Мое воображаемое решение - иметь массив объектов kdtree2 (по одному на поток). Для класса kdtree2_result_vector у меня пока нет решения, так как я не прошёл первую базу. Нет необходимости напрямую обращаться к классу kdtree2 .

Мне нужно только заполнить его данными и затем использовать их (так как вторая функция ниже является примером). Для этого я определил:

kdtree2 *global_kdtree2;

extern "C" void new_kdtree2 ( float **data, const int n, const int dim, bool arrange ) {

    multi_array_ref<float,2> kdtree2_data ( ( float * ) &data [ 0 ][ 0 ], extents [ n ][ dim ], c_storage_order ( ) );

    global_kdtree2 = new kdtree2 ( kdtree2_data, arrange );
}

Для того, чтобы затем использовать это дерево, я определил:

extern "C" void n_nearest_around_point_kdtree2 ( int idxin, int correltime, int nn ) { 

    kdtree2_result_vector result;

    global_kdtree2->n_nearest_around_point ( idxin, correltime, nn, result );
}

kdtree2_result_vector является производным от векторного класса. Он компилируется без ошибок, и получающаяся библиотека может быть связана, и ее C-функции доступны из C.

Проблема в том, что вызов n_nearest_around_point_kdtree2 приводит к сбою программы. Я подозреваю, что между настройкой дерева и использованием его во втором вызове функции дерево каким-то образом освобождается / уничтожается. Вызывающая c-test-программа размещена ниже:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "kdtree2.h"

#define MALLOC_2D(type,x,y) ((type**)malloc_2D_kdtree2((x),(y),sizeof(type)))

void **malloc_2D_kdtree2 ( const int x, const int y, const int type_size ) {

    const int y_type_size = y * type_size;

    void** x_idx = ( void ** ) malloc ( x * ( sizeof ( void ** ) + y_type_size ) );

    if ( x_idx == NULL )
        return NULL;

    char* y_idx = ( char * ) ( x_idx + x );

    for ( int i = 0; i < x; i++ )
        x_idx [ i ] = y_idx + i * y_type_size;

    return x_idx;
}

int main ( void ) {

    float **data = MALLOC_2D ( float, 100, 3 );

    for ( int i = 0; i < 100; i++ )
        for ( int j = 0; j < 3; j++ ) 
            data [ i ][ j ] = ( float ) ( 3 * i + j );

    // this works fine
    tnrp ( data, 100, 3, false );

    new_kdtree2 ( data, 100, 3, false );
    // this crashes the program
    n_nearest_around_point_kdtree2 ( 9, 3, 6 );

    delete_kdtree2 ( );

    free ( data );

    return 0;
}

Насколько я вижу, поиск в интернете должен работать, но мне явно не хватает чего-то жизненно важного в смелом (для меня) новом мире C ++.

EDIT:

Разрешение, благодаря Ларсманам. Я определил следующий класс (полученный от того, что larsmans опубликовал ранее):

class kdtree {

private:   

    float **data;
    multi_array_ref<float,2> data_ref;
    kdtree2 tree;

public:

    kdtree2_result_vector result;

    kdtree ( float **data, int n, int dim, bool arrange ) :

        data_ref ( ( float * ) &data [ 0 ][ 0 ], extents [ n ][ dim ], c_storage_order ( ) ),
        tree ( data_ref, arrange )
        {
        }

    void n_nearest_brute_force ( std::vector<float>& qv ) {
        tree.n_nearest_brute_force ( qv, result ); }

    void n_nearest ( std::vector<float>& qv, int nn ) {
        tree.n_nearest ( qv, nn, result ); }

    void n_nearest_around_point ( int idxin, int correltime, int nn ) {
        tree.n_nearest_around_point ( idxin, correltime, nn, result ); }

    void r_nearest ( std::vector<float>& qv, float r2 ) {
        tree.r_nearest ( qv, r2, result ); }

    void r_nearest_around_point ( int idxin, int correltime, float r2 ) {
        tree.r_nearest_around_point ( idxin, correltime, r2, result ); }

    int r_count ( std::vector<float>& qv, float r2 ) {
        return tree.r_count ( qv, r2 ); }

    int r_count_around_point ( int idxin, int correltime, float r2 ) {
        return tree.r_count_around_point ( idxin, correltime, r2 ); }
};

Код для вызова этих функций из C:

kdtree* global_kdtree2 [ 8 ];


extern "C" void new_kdtree2 ( const int thread_id, float **data, const int n, const int dim, bool arrange ) {

    global_kdtree2 [ thread_id ] = new kdtree ( data, n, dim, arrange );
}


extern "C" void delete_kdtree2 ( const int thread_id ) {

    delete global_kdtree2 [ thread_id ];
}


extern "C" void n_nearest_around_point_kdtree2 ( const int thread_id, int idxin, int correltime, int nn, struct kdtree2_result **result ) { 

    global_kdtree2 [ thread_id ]->n_nearest_around_point ( idxin, correltime, nn );

    *result = &( global_kdtree2 [ thread_id ]->result.front ( ) );
}

и в конечном итоге C-программа, чтобы начать использовать все это:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "kdtree2.h"


int main ( void ) {

    float **data = MALLOC_2D ( float, 100, 3 );

    for ( int i = 0; i < 100; i++ )
        for ( int j = 0; j < 3; j++ ) 
            data [ i ][ j ] = ( float ) ( 3 * i + j );

    int thread_id = 0;

    new_kdtree2 ( thread_id, data, 100, 3, false );

    struct kdtree2_result *result;

    n_nearest_around_point_kdtree2 ( thread_id, 28, 3, 9, &result );

    for ( int i = 0; i < 9; i++ )
        printf ( "result[%d]= (%d,%f)\n", i , result [ i ].idx, result [ i ].dis );

    printf ( "\n" );

    n_nearest_around_point_kdtree2 ( thread_id, 9, 3, 6, &result );

    for ( int i = 0; i < 6; i++ )
        printf ( "result[%d]= (%d,%f)\n", i , result [ i ].idx, result [ i ].dis );

    delete_kdtree2 ( thread_id );

    free ( data );

    return 0;
}

1 Ответ

3 голосов
/ 06 марта 2011

Документы API в ссылочной статье довольно ненадежны, и FTP-сервер автора не отвечает, поэтому я не могу с уверенностью сказать, но я догадываюсь, что

multi_array_ref<float,2> kdtree2_data((float *)&data[0][0], extents[n][dim],
                                      c_storage_order( ));

global_kdtree2 = new kdtree2(kdtree2_data, arrange);

создает kdtree2 путем сохранения ссылки на kdtree2_data в объекте global_kdtree2 вместо создания полной копии.Поскольку kdtree2_data является локальной переменной, она уничтожается при возврате new_kdtree2.Вы должны будете поддерживать его до тех пор, пока n_nearest_around_point_kdtree2 не будет сделано.

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