бросая экземпляр std :: length_error, пример требует boost

0

Это мой первый проект c++, поэтому может произойти сбой новичка. Все еще нужно многому учиться.

Я моделирую деревья (реальные деревья под открытым небом), устанавливая связанные цилиндры с облачной облачной библиотекой. В моем реальном сценарии я обнаруживаю около 3000 цилиндров, которые я хочу сохранить в структуре дерева (информатики) с двумя уровнями.

Я создаю родительские <-> дочерние отношения, если конечная точка и начальная точка совпадения двух цилиндров. Я начинаю с корневого цилиндра и обнаруживаю его детей. Для каждого ребенка это также выполняется рекурсивно. Пока цилиндр имеет только один ребенок, я добавляю его к так называемому сегменту с вектором цилиндров. Если размер детей детей равен 1, внук добавляется в тот же сегмент и так далее. Если цилиндр имеет более одного ребенка, текущий сегмент останавливается и для каждого ребенка создается новый сегмент. Все сегменты также имеют родительскую и дочернюю информацию, поэтому я могу выполнять итерацию по дереву в обоих направлениях.

Я создал минимальный пример для воспроизведения ошибки. Вместо 7 параметрических цилиндров мои тестовые цилиндры имеют только начало int и end int. Файл заголовка и cpp:

TestCylinder.h

#ifndef TESTCYLINDER_H
#define TESTCYLINDER_H


class TestCylinder
{
public:
int start;
int end;
TestCylinder(int a, int b);
virtual ~TestCylinder();
protected:
private:
};

#endif // TESTCYLINDER_H

TestCylinder.cpp

#include "TestCylinder.h"

TestCylinder::TestCylinder(int a, int b)
{
    start = a;
    end = b;
}

TestCylinder::~TestCylinder()
{
     //dtor
}

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

TestSegment.h:

#ifndef TESTSEGMENT_H
#define TESTSEGMENT_H

#include "TestCylinder.h"
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

class TestSegment
{
public:
    TestSegment(TestCylinder cylinder, boost::shared_ptr<TestSegment> parent);
    TestSegment(TestCylinder cylinder);
    TestSegment();
    virtual ~TestSegment();
    std::vector<TestCylinder> getCylinders();
    boost::shared_ptr<TestSegment> getParentSegment();
    std::vector<TestSegment> getChildSegments();
    bool addCylinder(TestCylinder nextCylinder);

protected:
private:
    std::vector<TestCylinder> cylinders;
    std::vector<TestSegment> childSegments;
    boost::shared_ptr<TestSegment>  parentSegment;
};

#endif // TESTSEGMENT_H

TestSegment.cpp:

#include "TestSegment.h"

TestSegment::TestSegment(TestCylinder cylinder)
{
    cylinders.empty();
    cylinders.push_back(cylinder);
}
TestSegment::TestSegment(TestCylinder cylinder, boost::shared_ptr<TestSegment> parent)
{
    cylinders.empty();
    cylinders.push_back(cylinder);
    parentSegment = parent;
}
TestSegment::~TestSegment()
{
}

std::vector<TestCylinder>
TestSegment::getCylinders()
{
    return cylinders;
}

boost::shared_ptr<TestSegment>
TestSegment::getParentSegment()
{
    return parentSegment;
}

std::vector<TestSegment>
TestSegment::getChildSegments()
{
    return childSegments;
}

bool TestSegment::addCylinder(TestCylinder nextCylinder)
{
    TestCylinder endCylinder = cylinders.back();
    int x1 = endCylinder.end;
    int x2 = nextCylinder.start;
    if(x1==x2)
    {
        cylinders.push_back(nextCylinder);
        return true;
    }
    return false;
}

И древовидный класс, который формирует древовидную структуру и предоставляет некоторые методы для итерации по сегментам/цилиндрам:

TestTree.h:

#ifndef TESTTREE_H
#define TESTTREE_H
#include "TestSegment.h"

class TestTree
{
public:
    TestTree(std::vector<TestCylinder> cylinders_in);
    virtual ~TestTree();

    /*
     * Getters and Setters
     */
    TestCylinder&
    getRootCylinder ();
    void
    setRootCylinder (TestCylinder rootCylinderNew);
    boost::shared_ptr<TestSegment>&
    getRootSegment ();
    void
    setRootSegment (boost::shared_ptr<TestSegment> rootSegmentNew);


    void addChildCylinders(TestCylinder& currentCylinder, TestSegment& segment);
    std::vector<TestCylinder>
    getChildCylinders(TestCylinder& currentCylinder);
    std::vector<TestSegment>
    getSegmentList ();
    std::vector<TestCylinder>
    getCylinderList ();

protected:
private:
    std::vector<TestCylinder> cylinders ;
    boost::shared_ptr<TestSegment> rootSegment;
    std::vector<TestSegment> getChildSegmentsRecursively(TestSegment parent);
};

#endif // TESTTREE_H

TestTree.cpp

#include "TestTree.h"


TestTree::TestTree(std::vector<TestCylinder> cylinders_in)
{
    cylinders = cylinders_in;
    TestCylinder rootCylinder = cylinders.at(0);
    TestSegment root(rootCylinder);
    rootSegment = boost::make_shared<TestSegment>(root);
    addChildCylinders(rootCylinder,*rootSegment);
}

TestTree::~TestTree()
{
    //dtor
}


std::vector<TestCylinder>
TestTree::getCylinderList ()
{

    std::vector<TestCylinder> cylinders;
    std::cout << "GetCylinderList before getSegmentsList" << "\n";
    std::vector<TestSegment> allSegments = getSegmentList();
    std::cout << "GetCylinderList after getSegmentsList" << allSegments.size()<<"\n";
    for(std::vector<TestSegment>::iterator it = allSegments.begin(); it!= allSegments.end(); ++it)
    {
        TestSegment segment = *it;
        //std::cout << segment.getSegmentCylinders().size();
        cylinders.insert(cylinders.end(),segment.getCylinders().begin(), segment.getCylinders().end());
    }
    return cylinders;
}

std::vector<TestSegment>
TestTree::getSegmentList ()
{
//    std::cout<<"GetSegmentList rootsegment size :"<< rootSegment->get.size()<<"\n";
    return getChildSegmentsRecursively(*rootSegment);
}

std::vector<TestSegment>
TestTree::getChildSegmentsRecursively(TestSegment parent)
{

    std::vector<TestSegment> allSegments;
    allSegments.push_back(parent);
    for(std::vector<TestSegment>::iterator it = parent.getChildSegments().begin (); it != parent.getChildSegments().end (); ++it)
    {
        TestSegment child = *it;
        std::vector<TestSegment> children = getChildSegmentsRecursively(child);
        allSegments.insert(allSegments.end(),children.begin(),children.end());
    }
    //std::cout << "TestTree geChildSegmentsRecursively" << parent.getChildSegments().size()<< "\n";
    return allSegments;
}


void TestTree::addChildCylinders(TestCylinder& currentCylinder, TestSegment& segment)
{
    std::vector<TestCylinder> children = getChildCylinders(currentCylinder);
    if(children.size()==1)
    {
        TestCylinder child = children.at(0);
        if(segment.addCylinder(child))
        {
        addChildCylinders(child,segment);
        }
    }
    else if (children.size()>1)
    {
        for (std::vector<TestCylinder>::iterator it = children.begin (); it != children.end (); ++it)
        {
            TestCylinder child = *it;
            boost::shared_ptr<TestSegment> seg_ptr = boost::make_shared<TestSegment>(segment);
            TestSegment childSegment (child, seg_ptr);
            if (childSegment.getParentSegment() == rootSegment)
            {
                std::cout << "TestTreeCpp::addChildCylinders, rootSegment is parentSegment \n";
            }
            addChildCylinders(child,childSegment);
        }
    }
}


std::vector<TestCylinder>
TestTree::getChildCylinders(TestCylinder& currentCylinder)
{
    std::vector<TestCylinder> children;

    for (std::vector<TestCylinder>::iterator it = cylinders.begin (); it != cylinders.end (); ++it)
    {
        TestCylinder cylinder = *it;
        if(currentCylinder.end == cylinder.start)
        {
            children.push_back(cylinder);
        }
    }
    return children;
}


/*
 * Getters and Setters
 */



TestCylinder&
TestTree::getRootCylinder ()
{
    TestSegment root = *rootSegment;
    return root.getCylinders().at(0);
}


boost::shared_ptr<TestSegment>&
TestTree::getRootSegment ()
{
    return rootSegment;
}

//void
//TestTree::setRootSegment (SegmentModel rootSegmentNew)
//{
//    rootSegment = rootSegmentNew;
//}

Основная функция, просто создавая 6 связанных цилиндров и вызывая дерево с этим списком:

int
main (int argc,
      char** argv)
{

    // ------------------------------------
    // -----Load Cherry 1             -----
    // ------------------------------------
    std::vector<TestCylinder> cylinders;
    TestCylinder cyl(0,1);
    cylinders.push_back(cyl);
    TestCylinder cyl2(1,2);
    cylinders.push_back(cyl2);
    TestCylinder cyl3(2,3);
    cylinders.push_back(cyl3);
    TestCylinder cyl4(3,4);
    cylinders.push_back(cyl4);
    TestCylinder cyl5(3,14);
    cylinders.push_back(cyl5);
    TestCylinder cyl6(14,15);
    cylinders.push_back(cyl6);

    std::cout << cylinders.size() << "\n";
    TestTree tree (cylinders);
    std::cout << tree.getCylinderList().size() << "\n";
}

Построение дерева может работать, при вызове функции getCylinderList возникает следующая ошибка:

terminate called after throwing an instance of 'std::length_error'
  what():  vector::_M_range_insert
Aborted (core dumped)

Возможная публикация не была полезной (для меня), поскольку я не добавляю или не удаляю элементы во время итерации.

  • 5
    Ужасно много кода здесь. Можете ли вы записать это до чего-то более простого и автономного?
  • 0
    Будет сложно сделать это проще, так как я думаю, что уже удалил ненужные функции из своего основного проекта. Может сделать каждую переменную общедоступной и тем самым избавиться от методов получения и установки. Самостоятельно вы имеете в виду, положить все в один файл, а также избавиться от заголовков?
Показать ещё 2 комментария
Теги:
boost
tree

1 ответ

6

Проблема в том, что TestSegment возвращает векторы по значению, например, в TestSegment :: getChildSegments. Это означает, что вы делаете копию вектора.

Теперь в getCylinderlist вы вызываете std :: vector :: insert (которая является функцией, упомянутой в сообщении об ошибке исключения) с параметрами segment.getCylinders(). Begin() и segment.getCylinders(). End(). Но эти два вызова getCylinders не возвращают один и тот же вектор, а скорее отдельные копии каждого из них. Итак, вы, по сути, говорите:

std::vector< TestCylinder > c1 = segment.getCylinders();
std::vector< TestCylinder > c2 = segment.getCylinders();
cylinders.insert( cylinders.end(), c1.begin(), c2.end() )

c1 и c2 не совпадают, поэтому код не работает.

Эта же проблема возникает с TestSegment :: getChildSegments.

Чтобы решить эту проблему, вы должны вернуть векторы const.

Надеюсь, это поможет.

  • 3
    Небольшое примечание (не связанное с проблемой): вызовы cylinders.empty (); не являются необходимыми и, вероятно, не тем, что вы хотите: - std :: vector всегда пуст после создания - std :: vector :: empty () просто сообщает вам, является ли вектор пустым, он не изменяет вектор. Вероятно, вы ищете функцию std :: vector :: clear
  • 0
    Спасибо за оба полезных комментария. Хотя я не загрузил мой код и уже покинул свой офис, так что я продолжу завтра.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню