我想使用std :: vector来控制给定的内存。首先,我很确定这不是一个好的做法,但好奇心对我来说更好,我想知道如何做到这一点。
我遇到的问题是这样的方法:
vector<float> getRow(unsigned long rowIndex)
{
float* row = _m->getRow(rowIndex); // row is now a piece of memory (of a known size) that I control
vector<float> returnValue(row, row+_m->cols()); // construct a new vec from this data
delete [] row; // delete the original memory
return returnValue; // return the new vector
}
_m是一个DLL接口类,它返回一个float数组,这是调用者要删除的责任。所以我想将它包装在一个向量中并将其返回给用户....但是这个实现为向量分配新的内存,复制它,然后删除返回的内存,然后返回向量。
我想要做的是直接告诉新的向量它可以完全控制这块内存,所以当它被删除时,内存会被清除。
更新:最初的动机(从DLL返回的内存)被一些响应者相当牢固地压扁了:)但是,无论如何,我很想知道这个问题的答案...有没有办法使用给定的一块预先分配的内存T *数组构造一个std :: vector,以及这个内存的大小?
答案 0 :(得分:5)
显而易见的答案是使用自定义分配器,但是您可能会发现这确实是您需要的重量级解决方案。如果你想这样做,最简单的方法是通过实现定义分配器(作为vector&lt;&gt;的默认第二个模板参数),复制它并使其按要求工作。
另一个解决方案可能是定义vector的模板特化,定义尽可能多的接口并实现内存定制。
最后,如何使用一致的STL接口定义自己的容器,定义随机访问迭代器等。这可能非常容易,因为底层数组将很好地映射到vector&lt;&gt;,并且指向它的指针将映射到迭代器。
对 UPDATE 的评论:“有没有办法使用给定的预分配内存T *数组块来构造std :: vector,以及这个内存的大小?”
这里简单的答案肯定是“不”。如果您希望结果是向量&lt;&gt;,那么它必须支持按需增长,例如通过reserve()方法,并且对于给定的固定分配是不可能的。所以真正的问题是:你究竟想要实现什么?可以像vector&lt;&gt;那样使用的东西,或某些意义上确实需要的东西是一个向量,如果有的话,那是什么意思?
答案 1 :(得分:4)
Vector的默认分配器不提供对其内部的这种类型的访问。您可以使用自己的分配器(向量的第二个模板参数)来完成它,但这会改变向量的类型。
如果你可以直接写入向量会更容易:
vector<float> getRow(unsigned long rowIndex) {
vector<float> row (_m->cols());
_m->getRow(rowIndex, &row[0]); // writes _m->cols() values into &row[0]
return row;
}
请注意,&amp; row [0]是一个浮点*,并且保证向量可以连续存储项目。
答案 2 :(得分:2)
这里要知道的最重要的事情是不同的DLL /模块具有不同的堆。这意味着需要从DLL中删除从DLL分配的任何内存(这不仅仅是编译器版本或delete
vs delete[]
或其他)。不要通过DLL边界传递内存管理责任。这包括在dll中创建std::vector
并返回它。但它还包括将std::vector
传递给DLL以由DLL填充;这样的操作是不安全的,因为您不确定std::vector
在填充值时不会尝试某种类型的调整。
有两种选择:
为使用分配函数的allocator
类定义自己的std::vector
,该函数保证驻留在创建向量的DLL / Module中。这可以通过动态绑定轻松完成(即,使allocator
类调用一些虚函数)。由于动态绑定将在函数调用的vtable中查找,因此可以保证它将落在最初创建它的DLL /模块的代码中。
不要将向量对象传递给DLL或从DLL传递。例如,您可以使用函数getRowBegin()
和getRowEnd()
返回行数组中的迭代器(即指针)(如果它是连续的),并让用户std::copy
进入其中自己的本地std::vector
对象。你也可以反过来做,将迭代器begin()和end()传递给像fillRowInto(begin, end)
这样的函数。
这个问题非常真实,尽管很多人在不知情的情况下忽略了它。不要低估它。我个人遭遇了与此问题相关的无声错误,并不是很漂亮!我花了几个月才解决它。
我已经检查了源代码,并且boost::shared_ptr
和boost::shared_array
使用动态绑定(上面的第一个选项)来处理这个问题。但是,它们不能保证是二进制兼容的。尽管如此,这可能是一个稍微好一点的选择(通常二进制兼容性比模块内存管理要小得多)。
答案 3 :(得分:0)
您最好的选择可能是std::vector<shared_ptr<MatrixCelType>>
。
this thread中有更多细节。
答案 4 :(得分:0)
如果您正在尝试更改向量分配/重新分配/释放内存的位置/方式,那么向量类的allocator模板参数就是您要查找的内容。
如果您只是想避免构造,复制构造,赋值和销毁的开销,那么允许用户实例化该向量,然后通过引用将其传递给您的函数。然后,用户负责构建和销毁。
听起来你正在寻找的是一种智能指针。一个删除它被摧毁时指向的东西。在这种情况下,请查看Boost库或自己动手。
答案 5 :(得分:0)
Boost.SmartPtr库包含许多有趣的类,其中一些专用于处理数组。
例如,看见scoped_array:
int main(int argc, char* argv[])
{
boost::scoped_array<float> array(_m->getRow(atoi(argv[1])));
return 0;
}
问题当然是scoped_array
无法复制,所以如果你真的想要std::vector<float>
,那么@Fred Nurk可能是你能得到的最好的。
在理想情况下,您希望等效于unique_ptr
,但需要数组形式,但我并不认为它是标准的一部分。