c++ - 运行 MEX 文件时 MATLAB 崩溃

标签 c++ matlab mex

我正在尝试编写一个 mex 文件,在计算 mex 时,每次运行 MATLAB 都会崩溃。这是我编写的 C++ 代码的一部分:

void mexFunction(mwSize nlhs, mxArray *plhs[],
             mwSize nrhs, const mxArray *prhs[]){   

vector<int> *NNLt;
double *NNLtout;
Vector *V;
Vector *Fb;
mwSize *sn;
mwSize nsn; 
mwSize nf; 
double hs;
double bw;
double mw; 
mwSize ncols; 
mwSize i;
double *NNLtoutt;

/* check for proper number of arguments */
if(nrhs!=9) {
    mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","Nine inputs required.");
}
if(nlhs!=1) {
    mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","One output required.");
}

/* get the value of the scalar input  */
nsn = mxGetScalar(prhs[4]);
nf = mxGetScalar(prhs[5]);
hs = mxGetScalar(prhs[6]);  
bw = mxGetScalar(prhs[7]);
mw = mxGetScalar(prhs[8]);
/* create a pointer to the real data in the input matrix  */
NNLt = (vector<int> *)mxGetData(prhs[0]);
V = (Vector *)mxGetData(prhs[1]);
Fb =(Vector *)mxGetData(prhs[2]);
sn = (mwSize *)mxGetData(prhs[3]); 

/* call the computational routine */    
createNNLtriangle(NNLt, V, Fb, sn, nsn, nf, hs, bw, mw);    

/* create the output matrix */
plhs[0] = mxCreateCellMatrix(nsn,50);

for(i=0;i<nsn;i++){
     mxArray* tmp = mxCreateDoubleMatrix(1, NNLt[i].size(), mxREAL);
     copy(NNLt[i].begin(), NNLt[i].end(), mxGetPr(tmp));     
     mxSetCell(plhs[0], i, tmp);
     mxFree(tmp);  
}}

所以,我收到以下错误:

------------------------------------------------------------------------
       Segmentation violation detected at Thu Aug  2 14:41:25 2018
------------------------------------------------------------------------
...
    Stack Trace (from fault):
[  0] 0x00007f0b0c635426 /home/user/dir/createNNLtriangle.mexa64+00005158
[  1] 0x00007f0b0c635893 /home/user/dir/createNNLtriangle.mexa64+00006291 mexFunction+00000240
[  2] 0x00007f0c562cac4a /home/user/bin/glnxa64/libmex.so+00142410 mexRunMexFile+00000090
...

对于我们造成的困惑,我们深表歉意,这里是我同事的澄清和其他问题。

您可以了解我们如何定义“NNLt”。这里的“tmp”是什么意思?

std::copy(mxGetPr(tmp), mxGetPr(tmp)+N, NNLt.begin());

下面是 Mexfile 中位于 MexFunction 之前的 cpp 函数:

#include "mex.h"
#include "matrix.h"
#include <omp.h>
#include "vema.h"s
#include "eig3.h"
#include <stdlib.h>
#include <iostream>
#include <cmath>
#include <vector>
#include <fstream>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>

using namespace std;

Vector closestPointTriangle(Vector&, Vector&, Vector&, Vector&, double&, double&, double&);

// Generates pomwSize-triangle proximity lists using the linked cell algorithm
void createNNLtriangle(vector<int>* NNLt, Vector* Ut, Vector* faces, int* SN, mwSize nsn, mwSize nf, double hs, double bw, double mw) {

int mx = max(1, (int)(bw/mw)); // ** = 40 cells bw=3.2, mw=0.08
vector<int> head(mx*mx*mx, -1);
vector<int> list(nf);
//  std::vector<int> head(mx*mx*mx, -1); //****** mx*mx*mx cells nomber, size mx*mx*mx vector with all values are -1, 40*40*40 = 64000
//  std::vector<int> list(nf); // **** nf = 101882
int xa, ya, za, xi, yi, zi;
double ub, vb, wb;
int pt, tri;
Vector cog;
for (int i = 0; i < nf; i++) { // Divide triangle faces mwSizeo cells, i index of face
    //Vector cog = (Ut[faces[i].n1] + Ut[faces[i].n2] + Ut[faces[i].n3])/3.0;
    cog = (Ut[(int)faces[i].x] + Ut[(int)faces[i].y] + Ut[(int)faces[i].z])/3.0;
    int xa = (int)((cog.x + 0.5*bw)/bw*mx);
    int ya = (int)((cog.y + 0.5*bw)/bw*mx);
    int za = (int)((cog.z + 0.5*bw)/bw*mx);
    int tmp =  mx*mx*za + mx*ya + xa; // *** 1641838 > 64000

    list[i]=head[mx*mx*za + mx*ya + xa];
    head[mx*mx*za + mx*ya + xa] = i;
}
#pragma omp parallel for
for (int i = 0; i < nsn; i++) { // Search cells around each pomwSize and build proximity list
    int pt = SN[i];
    NNLt[i].clear();
    int xa = (int)((Ut[pt].x + 0.5*bw)/bw*mx);
    int ya = (int)((Ut[pt].y + 0.5*bw)/bw*mx);
    int za = (int)((Ut[pt].z + 0.5*bw)/bw*mx);

    for (int xi = max(0, xa-1); xi <= min(mx-1, xa+1); xi++)// *** Browse head list
    for (int yi = max(0, ya-1); yi <= min(mx-1, ya+1); yi++)
    for (int zi = max(0, za-1); zi <= min(mx-1, za+1); zi++) {
        int tri = head[mx*mx*zi + mx*yi + xi];
        while (tri != -1) {
            if ( pt != (int)faces[tri].x && pt != (int)faces[tri].y && pt != (int)faces[tri].z ) {              
                if ( (closestPointTriangle(Ut[pt], Ut[(int)faces[tri].x], Ut[(int)faces[tri].y], Ut[(int)faces[tri].z], ub, vb, wb) - Ut[pt]).length() < hs) {
                    NNLt[i].push_back(tri);
                }
            }
            tri = list[tri];
        }
    }
    }
}


   // Returns the closest pomwSize of triangle abc to pomwSize p ***** a or b or c, if not, pt projection through the barycenter inside the triangle 
   Vector closestPointTriangle(Vector& p, Vector& a, Vector& b, Vector& c, double& u, double& v, double& w) {

Vector ab = b - a;
Vector ac = c - a;
Vector ap = p - a;
double d1 = ab.dot(ap);
double d2 = ac.dot(ap);
if (d1 <= 0.0 && d2 <= 0.0) {
    u = 1.0;
    v = 0.0;
    w = 0.0;
    return a;
}
Vector bp = p - b;
double d3 = ab.dot(bp);
double d4 = ac.dot(bp);
if (d3 >= 0.0 && d4 <= d3) {
    u = 0.0;
    v = 1.0;
    w = 0.0;
    return b;
}
double vc = d1*d4 - d3*d2;
if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) {
    v = d1 / (d1 - d3);
    u = 1.0 - v;
    w = 0.0;
    return a + ab * v;
}
Vector cp = p - c;
double d5 = ab.dot(cp);
double d6 = ac.dot(cp);
if (d6 >= 0.0 && d5 <= d6) {
    u = 0.0;
    v = 0.0;
    w = 1.0;
    return c;
}
double vb = d5*d2 - d1*d6;
if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) {
    w = d2 / (d2 - d6);
    u = 1.0 - w;
    v = 0.0;    
    return a + ac * w;
}
double va = d3*d6 - d5*d4;
if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0) {
    w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
    u = 0.0;
    v = 1.0 - w;
    return b + (c - b) * w;
}
double denom = 1.0 / (va + vb + vc);
v = vb * denom;
w = vc * denom;
u = 1.0 - v - w;
return a + ab * v + ac * w;
 }

下面是在Matlab中调用Mexfile的部分:

NNLt = cell(1,nsn);
V = A(1:n,1:3); //A: Matrix
Fb = A(n:2*n,1:3);
nf = size(Fb,1);
sn = B(1,:); //B: Matrix

parfor i = 1:nsn
     maxDist = max(maxDist, length(V(sn(i),:) - Vtold(i,:)));
end

if maxDist > 0.5*(hs-hc)
    [NNLt] = createNNLtriangle(NNLt, V, Fb, sn, nsn, nf, hs, bw, mw);
    for i = 1:nsn
        Vtold(i,:) = V(sn(i),:);
    end
 end

最后,这是用于定义 V 和 Fb 的“Vector*”类:

class Vector{
public:
double x, y, z;
Vector(): x(0.0), y(0.0), z(0.0) {};
Vector(double ax, double ay, double az): x(ax), y(ay), z(az) {};

double length(){
    return sqrt(x*x + y*y + z*z);
}
double dot(const Vector& b){
    return x*b.x + y*b.y + z*b.z;
}
Vector cross(const Vector& b){
    return Vector(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
}
void normalize(){
    double temp = 1.0/length();
    x *= temp;
    y *= temp;
    z *= temp;
}
void clear(){
    x = y = z = 0.0;
}
Vector& operator+= (const Vector& b){
    x += b.x;
    y += b.y;
    z += b.z;
    return *this;
}
Vector& operator-= (const Vector& b){
    x -= b.x;
    y -= b.y;
    z -= b.z;
    return *this;
}
Vector& operator*= (const double& c){
    x *= c;
    y *= c;
    z *= c;
    return *this;
}
Vector& operator/= (const double& c){
    x /= c;
    y /= c;
    z /= c;
    return *this;
}
Vector operator+ (const Vector& b){
    Vector r = *this;
    return r += b;
}
Vector operator- (const Vector& b){
    Vector r = *this;
    return r -= b;
}
Vector operator* (const double& c){
    Vector r = *this;
    return r *= c;
}
Vector operator/ (const double& c){
    Vector r = *this;
    return r /= c;
}
};

再次抱歉! 谢谢, 干杯

最佳答案

作为rahnema1 said in a comment , 你不能转换 mxGetData 的输出到您需要的任何指针类型。此输出指向 mxArray 的数据,你需要这样阅读它。

例如,

NNLt = (vector<int> *)mxGetData(prhs[0]);

A vector<int>是特定的 C++ 数据结构,您正在将 MATLAB 数组中的数据重新解释为 C++ 数据结构。此数据结构的元素之一是指向数据的指针,因此您正在将(大概) double 浮点值重新解释为指针,然后访问该指针,这显然会导致崩溃。

对于 Vector* 的转换也是如此,虽然我不知道这个类是什么。

相反,首先确保您的输入类型正确,然后复制数据:

if(!mxIsDouble(prhs[0])) {
   mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","First input must be a double array.");
}
std::size_t N = mxGetNumberOfElements(prhs[0]);
std::vector<int> NNLt(N);
std::copy(mxGetPr(prhs[0]), mxGetPr(prhs[0])+N, NNLt.begin());

但是,从您的其余代码来看,它似乎是 NNLt应该是 vector 的 vector ,而不是单个 vector 。是 createNNLtriangle函数取自 here ?这看起来像是 C 和 C++ 的可怕破坏......

也许你需要在这里做这样的事情:

if(!mxIsDouble(prhs[0])) {
   mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","First input must be a double array.");
}
std::size_t M = mxGetM(prhs[0]); // number of rows
std::size_t N = mxGetN(prhs[0]); // number of columns
std::vector<std::vector<int>> NNLt(N, std::vector<int>(M));
double* ptr = mxGetPr(prhs[0]);
for(std::size_t ii = 0; ii < N; ++ii) {
   std::copy(ptr, ptr+M, NNLt[ii].begin());
   ptr += M;
}

// mwSize nsn = static_cast<mwSize>(mxGetScalar(prhs[4])); // Ignore this value!

// ... read the other values here in the same way

createNNLtriangle(NNLt.data(), V, Fb, sn, N, nf, hs, bw, mw);
//                ^^^^^^^^^^^             ^--- NOTE!

还要注意第三个参数,Fb , 是一个 vector<Face> , 不是 Vector* .你必须弄清楚如何转换 Vector*vector<Face> ,它将涉及相当多的代码,而不仅仅是转换指针!

第 4 个参数是 int* , 不是 mwSize* :

sn = (mwSize *)mxGetData(prhs[3]); 

您需要确保 prhs[3]实际上包含一个 int32矩阵,那么你可以将它的指针指向一个 int* .否则,您必须像我们上面那样复制数据。

还要仔细检查所有其他参数,以确保您传递的类型正确。设置你的编译器来警告你所有的隐式转换,然后注意所有这些警告。这些警告中的每一个都是导致程序在运行时崩溃的潜在原因。全部修复!

关于c++ - 运行 MEX 文件时 MATLAB 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51655201/

相关文章:

matlab - 如何找出哪个变量触发了有关全局变量的 Matlab 警告

c++ - 读取 mex 文件中的结构数据时发生奇怪的事情

c++ - 如何使类静态变量线程安全

matlab - 如何使用 MATLAB 检查一个椭圆是否在另一个椭圆内?

linux - 在基于 linux 的集群 : matlab sessions stops before m file is completly executed 上调用 Matlab

multithreading - 创建的线程数为12,但仍只能在12个核心CPU的一个核心上运行

Matlab 在 RegressionTree mex 文件中崩溃

c++ - 如何将有界重复匹配为仅 n 和 m 次

C++如何初始化堆中的对象数组

c++ - 这些垃圾值从何而来?