如何在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 *。所以我猜一个人可以分配比所需更多的内存。我认为联合物可能值得一看。
答案 0 :(得分:5)
您可以使用您想要支持的每种类型的一个向量。
虽然这对void*
矢量的概念有很大的改进,但它仍然很臭。
这听起来像是一个 XY问题:你有一个问题X,你想象一个解决方案Y,但是如果没有某种巧妙的适应性,Y显然是行不通的,所以问一下Y.相反,应该询问真正的问题X.哪个是?
答案 1 :(得分:1)
好的,FWIW
我建议使用与malloc
结合的就地新内容。这样做可以让你在向量中存储创建为void*
的指针。然后当向量完成时,它可以简单地迭代并调用free()
。
即
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”类似的答案。
只是说';)
答案 2 :(得分:0)
“NVIDIA驱动程序”听起来像是一个C界面,所以malloc
并不是一个疯狂的建议。
另一种选择,正如你所建议的那样,是使用联合......但是你还需要在一个平行向量中存储“标签”来记录元素的实际类型,这样你就可以转换成适当的类型删除。
简而言之,您必须先将void *
转换为适当的类型,然后才能delete
它。 “C ++方式”将是一个带有虚拟析构函数的基类;当它指向任何子类的实例时,你可以调用delete
。但是,如果您使用的库已经确定了类型,那么这不是一个选项。
答案 3 :(得分: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指针可能基本上是免费的。
答案 4 :(得分:-1)
使用多个向量。保持vector<void*>
与API交谈(我猜测它需要一个连续的非均匀类型的void *?),但也有一个vector<std::unique_ptr<int>>
和vector<std::unique_ptr<float>>
拥有数据。当您创建new
int时,将拥有内存的unique_ptr
推送到vector
int
的{{1}},然后将其粘贴到与API兼容的vector
上}作为void*
。将三个vector
捆绑成一个struct
,以便在可能的情况下将它们的生命期联系在一起(并且可能是)。
您也可以使用存储变量所有权的单个向量来执行此操作。 vector
自制RAII伪 - unique_ptr
或shared_ptr
与自定义驱逐舰,或vector
std::function<void()>
您的“捆绑” struct的驱逐舰调用,或者你有什么。但我不建议这些选择。