具有给定内存的c ++向量构造

时间:2011-01-31 02:47:25

标签: c++ memory-management vector

我想使用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,以及这个内存的大小?

6 个答案:

答案 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_ptrboost::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,但需要数组形式,但我并不认为它是标准的一部分。