1

如何在 STL 容器中存储任意数量的动态创建的实例(不同类型的),以便以后只有容器才能释放内存?

它应该像这样工作:

std::vector< void * > vec;
vec.push_back( new int(10) );
vec.push_back( new float(1.) );

现在,如果vec超出范围,则指向实例的指针将被破坏,但不会释放int和的内存。float显然我不能这样做:

for( auto i : vec )
  delete *i;

因为void*不是指向对象的类型。

您可能会反对并争辩说这不是一个好主意,因为无法访问向量的元素。没错,我自己也不会访问它们。NVIDIA 驱动程序将访问它们,因为它只需要地址(void*很好)作为内核调用的参数。

我想这里的问题是它可以存储不同的类型。想知道如果union想将其作为参数传递给 cuda 内核,是否可以解决问题。

内核采用不同类型的参数,并通过遍历您事先不知道类型的表达式树(表达式模板)来收集。因此,在访问叶子时,您将存储参数。它只能是 void*,以及内置类型 int、float 等。

可以在内核启动后立即删除向量(启动是异步的,但驱动程序首先复制参数然后继续主机线程)。第二个问题:每个参数都传递一个 void* 给驱动程序。无论它是 int、float 还是 void*。所以我想一个人可以分配比需要更多的内存。我认为工会的东西可能值得一看。

4

5 回答 5

5

您可以使用您想要支持的每种类型的一个向量。

但是,虽然这对 的向量的想法有了很大的改进void*,但它仍然很臭。

这听起来确实像一个XY 问题:你有一个问题 X,你设想了一个解决方案 Y,但是如果没有某种巧妙的适应,Y 显然是行不通的,所以询问 Y。相反,应该询问真正的问题X. 哪个是?

于 2012-10-31T15:58:36.820 回答
1

好的,FWI

我建议使用就地 new 与malloc. 这样做是允许您将创建的指针存储void*在向量中。然后当向量完成时,可以简单地迭代并free()调用它。

IE

void* ptr = malloc(sizeof(int));
int* myNiceInt = new (ptr) int(myNiceValue);
vec.push_back(ptr);

//at some point later iterate over vec
free( *iter );

我相信这将是在这种情况下问题的最简单解决方案,但请接受这是一个类似“C”的答案。

只是在说' ;)

于 2012-10-31T16:38:59.480 回答
0

无论如何,“NVIDIA 驱动程序”听起来像一个 C 接口,所以malloc这不是一个疯狂的建议。

正如您所建议的,另一种选择是使用联合...但是您还需要将“标签”存储在并行向量中以记录元素的实际类型,以便您可以在删除时转换为适当的类型。

简而言之,您必须先强制void *​​转换为适当的类型delete。“C++ 方式”是拥有一个带有虚拟析构函数的基类;delete当它指向任何子类的实例时,您可以调用它。但是,如果您使用的库已经确定了类型,那么这不是一个选择。

于 2012-10-31T16:18:50.220 回答
0

如果您可以控制类型,则可以为它们创建一个抽象基类。给那个类一个虚拟析构函数。然后你可以让你的std::vector<Object*>和迭代它来删除任何继承自 Object 的东西。

您可能需要第二个std::vector<void*>指向实际值的指针,因为它Object*可能首先命中 vtable。第二个虚拟功能virtual void* ptr() { return &value; }在这里会很有用。如果它需要对象的大小,您也可以添加它。

您可以像这样使用模板模式:

template<typename T>
class ObjVal : public Object {
    public:
    T val;
    virtual void* ptr() { return &this->val; }
    virtual size_t size() { return sizeof(this->val); }
};

然后,您只需键入一次。

这不是特别有效的内存,因为每个 Object 至少为 vtable 选择一个额外的指针。

但是,new int(3)内存效率也不是很高,因为您的分配器可能使用超过 4 个字节。添加该 vtable 指针可能基本上是免费的。

于 2013-03-27T23:17:41.060 回答
-1

使用超过 1 个向量。保持与vector<void*>API 交谈(我猜这需要一个连续的非统一类型的 void*s 块?),但也有一个vector<std::unique_ptr<int>>并且vector<std::unique_ptr<float>>拥有数据。创建newint 时,将unique_ptr拥有内存的 a 推送到您vector的 of 中int,然后将其vector作为void*. 将三个vectorsstruct捆绑在一起,以便尽可能将它们的生命周期捆绑在一起(并且可能是)。

您也可以使用存储变量所有权的单个向量来执行此操作。一个vector你自己的 RAII 伪类unique_ptr,或者shared_ptr带有自定义的销毁器,或者你vectorstd::function<void()>“捆绑”结构的销毁器调用的一个,或者你有什么。但我不会推荐这些选项。

于 2012-10-31T16:07:42.520 回答