是否有可能在多个单元格中包含一个实例的返回单元格数组? [英] Is it possible return cell array that contains one instance in several cells?

查看:86
本文介绍了是否有可能在多个单元格中包含一个实例的返回单元格数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一些mex函数,必须返回庞大的字符串数组.

I write some mex function and have to return huge array of strings.

我这样做如下:

  mxArray * array = mxCreateCellMatrix(ARRAY_LEN, 1);
  for (size_t k = 0; k < ARRAY_LEN; ++ k) {
      mxArray *str = mxCreateString("Hello");
      mxSetCell(array, k, str);
  }
  prhs[0] = array;

但是,由于字符串始终具有相同的值,所以我只想创建它的一个实例. 像

However, since the string has always same value, I would like to create only one instance of it. like

  mxArray * array = mxCreateCellMatrix(ARRAY_LEN, 1);
  mxArray *str = mxCreateString("Hello");

  for (size_t k = 0; k < ARRAY_LEN; ++ k) {
      mxSetCell(array, k, str);
  }
  prhs[0] = array;

有可能吗?垃圾收集器如何知道释放它? 谢谢.

Does it possible? How the garbage collector knows to release it? Thank you.

推荐答案

您建议的第二个代码不安全,不应该使用,因为它可能会使MATLAB崩溃.相反,您应该写:

The second code you suggested is not safe and should not be used, as it could crash MATLAB. Instead you should write:

mxArray *arr = mxCreateCellMatrix(len, 1);
mxArray *str = mxCreateString("Hello");
for(mwIndex i=0; i<len; i++) {
    mxSetCell(arr, i, mxDuplicateArray(str));
}
mxDestroyArray(str);
plhs[0] = arr;

不幸的是,这不是内存存储的最有效使用.想象一下,我们没有使用一个很小的字符串,而是存储了一个非常大的矩阵(沿单元格重复).

This is unfortunately not the most efficient use of memory storage. Imagine that instead of using a tiny string, we were storing a very large matrix (duplicated along the cells).

现在可以执行您最初想要的操作,但是您将不得不诉诸于未记录在案的黑客(例如创建共享数据副本或手动增加mxArray_tag

Now it is possible to do what you initially wanted, but you'll have to be resort to undocumented hacks (like creating shared data copies or manually increment the reference count in the mxArray_tag structure).

实际上,这通常是在MATLAB中进行的.以这个为例:

In fact this is what usually happens behind the scenes in MATLAB. Take this for example:

>> c = cell(100,100);
>> c(:) = {rand(5000)};

您知道MATLAB中的单元格数组基本上是mxArray,其数据指针指向其他mxArray变量的数组.

As you know a cell array in MATLAB is basically an mxArray whose data-pointer points to an array of other mxArray variables.

在上述情况下,MATLAB首先创建与5000x5000矩阵相对应的mxArray.这将存储在第一个单元格c{1}.

In the case above, MATLAB first creates an mxArray corresponding to the 5000x5000 matrix. This will be stored in the first cell c{1}.

对于其余单元,MATLAB创建轻量级" mxArray,它们基​​本上与第一个单元元素共享其数据,即其数据指针指向包含巨大矩阵的同一块内存.

For the rest of the cells, MATLAB creates "lightweight" mxArrays, that basically share its data with the first cell element, i.e its data pointer points to the same block of memory holding the huge matrix.

因此,始终只有一个矩阵副本,除非您当然要修改其中一个(c{2,2}(1)=99),此时MATLAB必须取消链接"数组并为此单元格元素制作一个单独的副本

So there is only one copy of the matrix at all times, unless of course you modify one of them (c{2,2}(1)=99), at which point MATLAB has to "unlink" the array and make a separate copy for this cell element.

您会在内部看到每个mxArray结构都有一个参考计数器和一个交叉链接指针,以使这种数据共享成为可能.

You see internally each mxArray structure has a reference counter and a cross-link pointer to make this data sharing possible.

提示:您可以使用format debug研究此数据共享行为 选项打开,并比较各个指针的pr指针地址 细胞.

Hint: You can study this data sharing behavior with format debug option turned on, and comparing the pr pointer address of the various cells.

相同的概念对于结构字段也适用,因此在我们编写时:

The same concept holds true for structure fields, so when we write:

x = rand(5000);
s = struct('a',x, 'b',x, 'c',x);

所有字段都将指向x中的同一数据副本.

all the fields would point to the same copy of data in x..

我忘了显示我提到的未记录的解决方案:)

I forgot to show the undocumented solution I mentioned :)

#include "mex.h"

extern "C" mxArray* mxCreateReference(mxArray*);

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    mwSize len = 10;
    mxArray *arr = mxCreateCellMatrix(len, 1);
    mxArray *str = mxCreateString("Hello");
    for(mwIndex i=0; i<len; i++) {
        // I simply replaced the call to mxDuplicateArray here
        mxSetCell(arr, i, mxCreateReference(str));
    }
    mxDestroyArray(str);
    plhs[0] = arr;
}

MATLAB

>> %c = repmat({'Hello'}, 10, 1);
>> c = mex_test()
>> c{1} = 'bye'
>> clear c

mxCreateReference函数将在每次调用str数组时增加其内部引用计数器,从而使MATLAB知道该数组还有其他副本.

The mxCreateReference function will increment the internal reference counter of the str array each time it is called, thus letting MATLAB know that there are other copies of it.

因此,当您清除生成的单元格数组时,它将依次为每个单元格将该计数器减一,直到计数器达到0为止,此时可以安全地销毁相关数组.

So when you clear the resulting cell arrays, it will in turn decrement this counter one for each cell, until the counter reaches 0 at which point it is safe to destroy the array in question.

直接使用数组(mxSetCell(arr, i, str))是有问题的,因为引用计数器在破坏第一个单元格后立即达到零.因此,对于后续单元,MATLAB将尝试释放已经释放的数组,从而导致内存损坏.

Using the array directly (mxSetCell(arr, i, str)) is problematic because the ref-counter immediately reaches zero after destroying the first cell. Thus for subsequent cells, MATLAB will attempt to free arrays that have already been freed, resulting in memory corruption.

这篇关于是否有可能在多个单元格中包含一个实例的返回单元格数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆