2015-10-03 3 views
1

Сначала немного:Как правильно управлять вектором пустых указателей

Я работаю над проектом, который требует, чтобы я моделировать взаимодействия между объектами, которые можно рассматривать в качестве полигонов (обычно треугольников или четырехугольников , почти наверняка меньше семи сторон), каждая из которых состоит из радиуса двух кругов с переменным (и, возможно, нулевым) числом «рек» различной постоянной ширины, проходящей между ними, и из многоугольника через какой-то другой боковая сторона. Поскольку эти реки и круги и их ширина (и положения кругов) указаны во время выполнения, один из этих многоугольников с N сторонами и протекающими через него реками M может быть полностью описан массивом указателей N + 2M, каждый из которых ссылается на соответствующие реки/круги, начиная с произвольного угла многоугольника и проходящего вокруг (в принципе, поскольку реки не могут пересекаться, они должны быть уточнены с меньшим количеством данных, но на практике я не уверен, как это реализовать).

Я изначально программировал это на Python, но быстро обнаружил, что для более сложных мероприятий производительность была неприемлемо медленной. Перенесив это на C++ (выбранный из-за его переносимости и совместимости с SDL, который я использую для рендеринга результата после завершения оптимизации), я немного теряю, как иметь дело с структурой многоугольника.

Очевидное, что нужно сделать для них класс, но поскольку на C++ отсутствуют даже массивы времени выполнения или массивы с несколькими типами, единственный способ сделать это будет с нелепо громоздким набором векторов, описывающих список кругов, рек и их относительного размещения, или еще более громоздкий «краевой» класс. Вместо этого кажется, что лучшим вариантом является использование гораздо более простого, хотя и все еще раздражающего, вектора указателей пустот, каждый из которых указывает на реки/круги, как описано выше.

Теперь вопрос:

Если я правильно, надлежащим образом обрабатывать соответствующие распределения памяти здесь с минимальным количеством путаницы (не говоря много ...) что-то вроде этого:

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++ позволит мне это сделать, или есть способ избежать какой-либо конструкции кольцевой развязки?

И если вы ответ будет что-то вроде «не используют недействительные указатели» или «просто сделать класс многоугольник», если вы не можете объяснить, как это сделает проблему проще, сохранить себя беда. Я единственный, кто когда-либо увидит этот код, поэтому я не забочусь о том, чтобы придерживаться лучших практик. Если я забуду, как/почему я что-то сделал, и это вызывает у меня проблемы позже, это моя собственная ошибка для недостаточно документирования, а не повод написать это по-другому.

редактировать Так, по крайней мере один человек спросил, вот мой оригинальный питон, обработка части создания полигона/оценки процесса:

#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. 
+1

Почему указатели void?Почему не вектор указателей какого-то базового класса с виртуальными методами? –

+0

Если вы выделяете что-либо в куче, оно будет * не * освобождено, когда вы выйдете из области видимости. Вы должны обернуть его в какой-то объект менеджера, который выполняет итерацию, и 'delete' все, что вы выделили. Как правило, любой вызов распределения через 'new' должен быть освобожден через вызов' delete', когда вы закончите –

+0

Вероятно, самая большая причина не использовать указатели void - это то, что вы отказываете компилятору в возможности ловить ошибки, которые вы могли бы сделать с назначением указателя. –

ответ

0

Пустота в качестве аргумента шаблона должна быть в нижнем регистре. Помимо этого он должен работать, но я также рекомендую использовать для этого базовый класс. С помощью умного указателя вы можете позволить системе обрабатывать все управление памятью.

+0

Ну, теперь я действительно смущен. Если то, что у меня уже есть, указатели void и все, должны работать, то какое управление памятью есть для системы? Мне все равно нужно сделать все указатели и вручную добавить их к вектору, и если вы правы, мне не нужно их вручную удалять, так какая фактическая польза для создания совершенно нового, в противном случае бессмысленного базового класса? –