从C崩溃应用程序使用全球C++对象

问题描述:

这是我的第一篇文章,我是这个网站的新手,但我一直潜伏了一段时间。我对C有很好的了解,并且对C++的知识非常有限。我猜。我在Windows(XPx64),VS2008上。从C崩溃应用程序使用全球C++对象

我想包装一个C++库kdtree2,以便我可以从C中使用它。主要问题与访问kdtree2和kdtree2_result_vector类有关。由于作者ftp服务器没有响应我已经上传了一份原始发行版本kdtree2 src

只需在kd-tree(二叉树的一种形式)上的一些快速信息,“'数据'是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从vector类。这编译没有错误,并且可以链接生成的库,并且可以从C访问C函数。

问题是调用n_nearest_around_point_kdtree2会使程序崩溃。我怀疑设置树并在第二个函数调用中使用它,树以某种方式被释放/销毁。在调用C-测试程序下面贴:

#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++。

编辑:

决议,由于larsmans。我定义下面的类(从早期什么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; 
} 
+0

什么是崩溃的堆栈跟踪? – outis 2011-03-06 14:18:36

+0

似乎对我来说......如果你能为每个人提供一个最小的测试用例来重现这个错误,它会更容易帮助你 – Constantin 2011-03-06 14:20:14

被引用论文的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通过在global_kdtree2对象存储到kdtree2_data的引用,而不是使一个完整副本。由于kdtree2_data是局部变量,因此在new_kdtree2返回时会被销毁。您必须保持活动状态,直到n_nearest_around_point_kdtree2完成。

+0

你的分析似乎是正确的,但如何实现这一点? – degski 2011-03-06 14:27:15

+0

@degski:由于您使用的是全局对象,因此您可能也希望将关联的数据全局化。在'new_kdtree2'函数中创建全局副本。 – 2011-03-06 14:30:45

+0

编译器生成:“kdtree2”的复制赋值运算符因为成员“kdtree2 :: the_data”具有引用类型而被压制。因此,似乎不可能将整个事物复制到全局变量(但是,我在这里游泳!)... – degski 2011-03-06 14:36:31