gpt4 book ai didi

c++ - nanoflann kdtree 适配器引发段错误

转载 作者:行者123 更新时间:2023-11-28 01:37:14 25 4
gpt4 key购买 nike

我正在尝试在我的类(class)中使用 nanoflann 的 kdtree 结构。我有以下 kdtree 适配器的 header ,它只是 this 的一个小(可能是坏的)变体。 ,应该允许以 3d vector 作为元素的 kd 树结构:

// "KdVec3dAdaptor.h"
#include "nanoflann.hpp"
#include <vector>


using Distance = nanoflann::metric_L2; // Was in template before, dont need it, this way its easier to read
using VectorOfVectorsType = std::vector<std::array<double,3>>;

template <class VectorOfVectorsType>
struct KdVec3dAdaptor
{
typedef KdVec3dAdaptor<VectorOfVectorsType> self_t;
typedef typename Distance::template traits<double,self_t>::distance_t metric_t;
typedef nanoflann::KDTreeSingleIndexAdaptor< metric_t,self_t,3,size_t> index_t;

VectorOfVectorsType m_data;
index_t* index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index.

KdVec3dAdaptor() = default;

KdVec3dAdaptor(const VectorOfVectorsType &mat, const int leaf_max_size = 10) : m_data(mat)
{
const size_t dims = mat[0].size();
index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size ) );
index->buildIndex();
}

~KdVec3dAdaptor()
{ // destructor
delete index;
}

KdVec3dAdaptor& operator=(KdVec3dAdaptor&& other)
{ // move assignment operator
if (this != &other)
{ // check that no self-assignment is performed
delete index;
index = other.index;
m_data = other.m_data;
other.index = nullptr;
}
return *this;
}

const self_t & derived() const
{
return *this;
}
self_t & derived()
{
return *this;
}

inline size_t kdtree_get_point_count() const
{// Must return the number of data points
return m_data.size();
}

inline double kdtree_get_pt(const size_t idx, int dim) const
{ // Returns the dim'th component of the idx'th point in the class
return m_data[idx][dim];
}

template <class BBOX>
bool kdtree_get_bbox(BBOX & /*bb*/) const
{ // return false to default to a standard bbox computation loop.
return false;
}
};

我面临的问题是使用这个 kdtree 结构作为一个类的成员变量。具有所需类型定义的该类的最小版本是:

// "test.cpp"
#include <iostream>
#include <array>
#include "KdVec3dAdaptor.h"

const int dimens = 3;
using vec3d = std::array<double, dimens>;
using vec_arr = std::vector<vec3d>;
using my_kd_tree = KdVec3dAdaptor<vec_arr>;

class foo
{
public:
const int n;
const double level;
my_kd_tree init_ps_tree;

foo(const int &N, const double &level, vec_arr &kset)
:n(N), level(level)
{
init_ps_tree = my_kd_tree(kset,10);
}
};

树是在类的不同方法中声明的(我使用另一个类型为 vec_arr 的类变量来构成树点)。现在这是我在跟踪错误时迷路的地方。当我尝试调用以下方法时:

void test()
{
double level = -0.3;
std::vector<double> arr1 {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1};
std::vector<double> arr2 {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1};
vec3d vec1 {{1.0, 0.0, 0.0}};
vec3d vec2 {{1.0, 0.0, 0.0}};
vec3d vec3 {{1.0, 0.0, 0.0}};
vec3d vec4 {{1.0, 0.0, 0.0}};
vec3d vec5 {{1.0, 0.0, 0.0}};
vec3d vec6 {{1.0, 0.0, 0.0}};
vec3d vec7 {{1.0, 0.0, 0.0}};
vec3d vec8 {{1.0, 0.0, 0.0}};
vec_arr vecarr1 {vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8};

int N = 5;
vec_arr init_points;

foo entity(N, level, kset);
std::cout << entity.n << std::endl;
}

我收到一个段错误,我认为这一定是由于 kdtree 结构的 header 引起的。但是,我无法进一步追踪它,因为:

  • 在 main 方法中做完全相同的事情工作得很好,只有在其他地方做这件事时才会出现错误
  • 无需访问任何类实例,代码编译正常
  • 删除任何未使用的 vec3d 变量可以解决问题(如您所猜,我稍后会在该方法的某个地方需要它们)
  • 即使有更多成员变量,有时从类中删除其他成员变量(如 leveln)也能解决问题
  • 使用 new 创建实例不会改变任何东西
  • 摆脱类中的任何成员变量可以解决问题(但实际上我在项目的其他地方需要它们)

我忽略了什么? KdVec3dAdaptor 中的析构函数有问题吗?我敢肯定这一定是愚蠢的事情。在此先感谢您提供的任何帮助和建议。

最佳答案

您正在删除未创建的对象。查看 KdVec3dAdaptor 类的析构函数。在 test 函数中你创建了 foo 对象

foo entity(N, level);

在这个构造函数中 my_kd_tree init_ps_tree; 成员是通过使用 KdVec3dAdaptor 的默认构造函数创建的,它没有设置 index 成员。当test函数结束时,foo析构函数被调用,init_ps_tree被销毁,但是index没有被设置,并且

delete index;

KdVec3dAdaptor 中的析构函数会使您的程序崩溃。在 KdVec3dAdaptor 的默认构造函数中,您应该将 index 成员设置为 0。

编辑

我不知道你为什么将默认构造函数的定义保留为

KdVec3dAdaptor() = default;

在进入 foo 构造函数的主体之前,查看 foo 构造函数的定义

{
init_ps_tree = my_kd_tree(kset,10); // [1] init_ps_tree was already created
}

对象 init_ps_tree 是使用默认构造函数创建的(index 成员可能包含垃圾数据 - 随机值,如果此对象被创建为局部变量)。在这一行中 [1] 移动赋值运算符被调用,下面的行将被执行

delete index;  // very dangerous

您可以在空指针上调用 delete,但在您的情况下我们不知道 index 持有什么值。首先,将KdVec3dAdaptor的ctor写成

KdVec3dAdaptor::KdVec3dAdaptor() : index(0) {}

接下来,在您的移动赋值运算符中,您应该使用 std::move 来移动 vector 数据,现在创建 vector 的拷贝。

    if (this != &other)
{ // check that no self-assignment is performed
delete index;
index = other.index;
m_data = std::move(other.m_data); // [2] this vector can be moved
other.index = nullptr;
}

关于c++ - nanoflann kdtree 适配器引发段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48760852/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com