c++ - 为什么指针的值会意外改变?

标签 c++ matlab pointers memory mex

我已经将 C++ 集成到 Matlab 中;在我的例子中有三个简单的文件:一个 Matlab 脚本 main.m,一个 Matlab 类文件 myClass.m 和一个 C++ 文件 myMex.cpp.

main.m 中,我调用类并给出一个字符串作为输入。

main.m:

myVar = myClass('test.bin');

myClass.m:

classdef myClass < handle    
    properties
        bitStreamName;
        cabac_handle;
    end
    methods
        function obj = myClass(fn)      
            obj.bitStreamName = fn;
            obj.cabac_handle = myMex('First', obj.bitStreamName);
            myMex('Second', obj.cabac_handle);
        end
    end
end

myMex.cpp:

#include "mex.h"
#include <iostream>
using namespace std;

void _main();

class CABAC {
public:
    CABAC() {};
    ~CABAC() {};
    char* fn;
};

// the MEX interface function
void mexFunction(
    int nlhs, // Number of expected output mxArrays
    mxArray *plhs[], // Array of pointers to the expected output mxArrays
    int nrhs, // Number of input mxArrays
    const mxArray *prhs[] // Array of pointers to the input mxArrays
    )

{
    CABAC *c; // pointer to (new) instance of the CABAC class
    char* fn = 0;
    char cmd[64]; // temp char array to hold the command

    // start parsing the input command
    mxGetString(prhs[0], cmd, sizeof(cmd));
    string inputCmd(cmd);

    if (inputCmd == "First")
    {
        // get the filename string
        fn = mxArrayToString(prhs[1]);
        c = new CABAC;
        uintptr_t c_value = (uintptr_t)c;
        plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
        *mxGetPr(plhs[0]) = c_value; // return pointer to matlab environment
        c->fn = fn;
        mexPrintf("Pointer: %p\n", c);
        mexPrintf("Filename: %s\n", c->fn);
    }
    else if (inputCmd == "Second")
    {
        uintptr_t my_value = *mxGetPr(prhs[1]);
        CABAC *my_pointer =  (CABAC *)my_value;
        mexPrintf("Pointer: %p\n", my_pointer);
        mexPrintf("Filename: %s\n", my_pointer->fn);
    }
}

第一次调用 myMex.cpp 时,我创建了一个类 CABAC 的对象,字符串 "test.bin" 是关联到它的属性 fn。最后将指针的值返回给Matlab环境。

第二次,我只是得到了指向先前实例化对象的指针,这里发生了一些奇怪的事情。特别是,同时打印指针的地址和属性 fn,前者总是正确的(即对象的地址相同),但后者有时是正确的( “test.bin” 被打印),有时完全随机错误(出现奇怪的字符串,每次执行都不同)。

要执行我的代码,您可以在使用以下指令编译 myMex.cpp 后简单地运行 main.m:

mex CXXFLAGS="\$CXXFLAGS -std=c++11" -g myMex.cpp

mex COMPFLAGS="\$CXXFLAGS -std=c++11" -g myMex.cpp

你能帮我理解文件名发生了什么吗?

编辑:似乎 c 在第一次 myMex 调用后被删除。如何将指向 CABAC 对象(及其所有属性)的指针保存在内存中?

最佳答案

这里有很多问题。首先,您将一个指向 double 的指针强制转换,它不会保留其表示形式:

uintptr_t c_value = (uintptr_t)c;
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
*mxGetPr(plhs[0]) = c_value; // return pointer to matlab environment

相反,创建一个 64 位整数数组以将指针保存到:

plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
*(uint64_t*)mxGetData(plhs[0]) = (uint64_t)c;

(因为 MATLAB R2018a 有 alternatives to mxGetData for each type ,在这种情况下它将是 mxGetUint64s)。

其次,当 MEX 文件被卸载时,内存 newed 可能会被删除。这随时可能发生。为防止这种情况,请使用 mexLock 将 MEX 文件锁定在内存中.为防止内存泄漏,您需要包含在用完内存后删除内存的代码。由于您的 MATLAB 类是句柄类,因此可以完成此操作。

第三,很容易用错误的指针调用 MEX 文件,这很可能会使整个 MATLAB 崩溃。您当前的实现无法解决这个问题。

第四,正如Navan所指出的, 以下行创建字符串的拷贝,但在 MATLAB 维护的内存缓冲区中:

fn = mxArrayToString(prhs[1]);

MATLAB 会自动删除由 mxMalloc 分配的所有内存以及 mexFunction 末尾的类似内存。因此,fn 将指向释放的内存。您需要在您管理的内存中手动创建一个拷贝。我建议您将字符串复制到 std::string 中:

class CABAC {
  public:
  std::string fn;
};

fn = mxArrayToString(prhs[1]); // Will copy the string to `fn`.

但是,我会推荐一种不同的方法:

  • 在您的 MEX 文件中,保留指向已分配对象的指针数组。
  • MEX 文件不返回指针,而是返回数组索引。
  • MEX 文件现在可以测试输入“句柄”是否在数组的有效范围内,以及该数组是否包含有效指针或 NULL 指针(例如,对于已删除的对象或用于尚未使用的数组元素)。
  • 锁定 MEX 文件,但允许命令解锁它。解锁 MEX 文件也会删除所有分配的对象。
  • 您可以包含在删除最后一个分配的对象时自动解锁 MEX 文件的逻辑。

您应该知道全局变量将在对 MEX 文件的调用之间持续存在(只要它被锁定)。因此,您需要一个全局数组(在 mexFunction 之外定义)来存储指针。或者,在 mexFunction 中声明数组 static .

This MEX-file实现了这里描述的建议,虽然它远非一个简单的例子,但我希望它可以作为一个有用的起点。在此函数中,我使用 std::map 而不是普通数组来存储句柄。

关于c++ - 为什么指针的值会意外改变?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54072118/

相关文章:

C++取消引用未分配的内存但没有段错误

c++ - OpenCV如何在matlab中共享库?

c - 字节似乎被转移了

c++ - 验证取自 std::cin 的 char * 的长度

c++ - 是否定义为 C++ 标准算法提供倒置范围?

c++ - 在析构函数中使用 "this"

matlab - 为什么/什么时候我应该更喜欢 MATLAB 而不是 Octave?

matlab - 无法使用 MATLAB MapReducer 2014b 中的 'local' 配置文件启动并行池

c++ - C++ 和 C 中指针和数组的区别

c++ - std::map 迭代器到自身