【问题标题】:How to properly manage a vector of void pointers如何正确管理 void 指针向量
【发布时间】:2015-12-31 08:29:23
【问题描述】:

首先,一些背景:

我正在做一个项目,该项目需要我模拟可以被视为多边形的对象之间的交互(通常是三角形或四边形,几乎可以肯定少于七个边),每个边由两个半径组成具有可变(可能为零)数量的各种恒定宽度的“河流”的圆圈在它们之间通过,并通过另一边离开多边形。由于这些河流和圆以及它们的宽度(以及圆的位置)是在运行时指定的,因此这些具有 N 条边和 M 条河流的多边形中的一个可以完全由 N+2M 指针数组来描述,每个指针指相关的河流/圆圈,从多边形的任意角开始并经过(原则上,由于河流不能重叠,它们应该可以用更少的数据来指定,但实际上我不确定如何实现)。

我最初是用 Python 编程的,但很快发现对于更复杂的安排,性能慢得令人无法接受。在将其移植到 C++ 时(选择它是因为它的可移植性和与 SDL 的兼容性,一旦优化完成,我就使用它来呈现结果)我对如何处理多边形结构有些茫然。

显而易见的事情是为它们创建一个类,但由于 C++ 甚至缺少运行时大小的数组或多类型数组,唯一的方法是使用一组非常繁琐的向量来描述圆圈,河流及其相对位置,或者某种更繁琐的“边缘”类。与此不同,似乎更好的选择是使用更简单但仍然很烦人的 void 指针向量,每个指针都指向如上所述的河流/圆圈。

现在,问题来了:

如果我是正确的,在这里处理相关内存分配的正确方法是尽量减少混乱(不多说......)是这样的:

int doStuffWithPolygons(){
    std::vector<std::vector<void *>> polygons;
    while(/*some circles aren't assigned a polygon*/){
        std::vector<void *> polygon;
        void *start = &/*next circle that has not yet been assigned a polygon*/;
        void *lastcircle = start;
        void *nextcircle;
        nextcircle = &/*next circle to put into the polygon*/;
        while(nextcircle != start){
            polygon.push_back(lastcircle);
            std::vector<River *> rivers = /*list of rivers between last circle and next circle*/;
            for(unsigned i = 0; i < rivers.size(); i++){
                polygon.push_back(rivers[i]);
            }
            lastcircle = nextcircle;
            nextcircle = &/*next circle to put into the polygon*/;
        }
        polygons.push_back(polygon);
    }

    int score = 0;
    //do whatever you're going to do to evaluate the polygons here
    return score;
}

int main(){
    int bestscore = 0;
    std::vector<int> bestarrangement; //contains position of each circle
    std::vector<int> currentarrangement = /*whatever arbitrary starting arrangement is appropriate*/;
    while(/*not done evaluating polygon configurations*/){
        //fiddle with current arrangement a bit
        int currentscore = doStuffWithPolygons();
        if(currentscore > bestscore){
            bestscore = currentscore;
            bestarrangement = currentarrangement;
        }
    }

    //somehow report what the best arrangement is

    return 0;
}

如果我正确理解这些东西是如何处理的,我就不需要任何 delete 或 .clear() 调用,因为在函数调用之后一切都超出了范围。我对此是否正确?另外,上面是否有任何部分不必要地复杂,或者不够复杂?我是否认为这就像 C++ 让我做到的一样简单,或者有什么方法可以避免一些迂回结构?

如果你的回答是“不要使用 void 指针”或“只创建一个多边形类”,除非你能解释它如何使问题变得更简单 ,省去自己的麻烦。我是唯一一个会看到这段代码的人,所以我不在乎遵守最佳实践。如果我忘记了我是如何/为什么做某事的,并且后来给我带来了问题,那是我自己的错误,因为没有充分记录它,而不是用不同的方式写它的理由。

编辑 由于至少有人问过,这是我原来的 python,处理过程中的多边形创建/评估部分:

#lots of setup stuff, such as the Circle and River classes

def evaluateArrangement(circles, rivers, tree, arrangement): #circles, rivers contain all the circles, rivers to be placed. tree is a class describing which rivers go between which circles, unrelated to the problem at hand. arrangement contains (x,y) position of the circles in the current arrangement.
    polygons = []
    unassignedCircles = range(len(circles))
    while unassignedCircles:
        polygon = []
        start = unassignedCircles[0]
        lastcircle = start
        lastlastcircle = start
        nextcircle = getNearest(start,arrangement)
        unassignedCircles.pop(start)
        unassignedCircles.pop(nextcircle)
        while(not nextcircle = start):
            polygon += [lastcircle]
            polygon += getRiversBetween(tree, lastcircle,nextcircle)
            lastlastcircle = lastcircle
            lastcircle = nextcircle;
            nextcircle = getNearest(lastcircle,arrangement,lastlastcircle) #the last argument here guarantees that the new nextcircle is not the same as the last lastcircle, which it otherwise would have been guaranteed to be.
            unassignedCircles.pop(nextcircle)
        polygons += [polygon]
    return EvaluatePolygons(polygons,circles,rivers) #defined outside.

【问题讨论】:

  • 为什么是空指针?为什么不使用带有虚拟方法的某些基类类型的指针向量?
  • 如果你在堆上分配了任何东西,当你超出范围时它不会被释放。您必须将它包装在某种迭代的管理器对象中,并 deletes 您分配的任何内容。根据经验,通过new 的任何分配调用都应在完成后通过delete 调用解除分配
  • 不使用 void 指针的最大原因可能是因为您拒绝编译器捕获指针赋值时可能出现的错误。
  • 也许您可以显示您尝试移植的 python 代码。应该有一种方法可以进行非常直接的转换。
  • @Joel Cornett:共享或唯一指针向量在自动垃圾收集方面是否有效?

标签: c++ memory-management vector void-pointers


【解决方案1】:

Void 作为模板参数必须是小写。除此之外它应该可以工作,但我也建议为此使用基类。使用智能指针,您可以让系统处理所有内存管理。

【讨论】:

  • 好吧,现在我真的很困惑。如果我已经拥有的 void 指针和所有东西应该可以工作,那么系统需要处理哪些内存管理?我仍然需要创建所有指针并手动将它们添加到向量中,如果你是对的,我不需要手动删除它们,那么创建一个全新的、否则毫无意义的基类有什么实际好处?
猜你喜欢
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-19
  • 2013-05-15
  • 2018-10-14
  • 2015-02-03
相关资源
最近更新 更多