Проблема вектора указателей - PullRequest
0 голосов
/ 28 марта 2009

У меня немало проблем с попыткой push_back объекта моего пользовательского класса к вектору указателей с моим пользовательским классом в качестве типа. Пожалуйста, смотрите код ниже вместе с полученной ошибкой. Я использую Eclipse с плагином CDT и OpenCV на Windows XP.

Я потратил так много времени, пытаясь найти ответ, но безрезультатно! ps Я студент, и указатели и т. д. не мое дело!

    std:: vector<RoadLine>* LaneChangeDetector::roadLines(IplImage* img_8uc1, IplImage* img_8uc3, IplImage* img_edge, std::vector <RoadLine>* roadVector){

    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* lines = 0;
    CvMemStorage* roadStorage = cvCreateMemStorage(0);
    CvSeq* roadLines = 0;

    // Probabalistic Hough transform returns line segments from edge detected image
    lines = cvHoughLines2( img_edge, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 50, 200, 200 );

    // Sequence roadlines, lines with correct slope are added to this sequence
    roadLines = cvCreateSeq(0, lines->header_size, lines->elem_size, roadStorage);

    // slope
    double m = 0.0;

    // Point of intersection
    CvPoint poi;

    for(int i = 0; i < lines->total; i++ ){
        CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
        CvPoint pt1 = line[0];
        CvPoint pt2 = line[1];

        double x1 = double(pt1.x);
        double y1 = double(pt1.y);
        double x2 = double(pt2.x);
        double y2 = double(pt2.y);

        if(pt1.x == pt2.x){
            m = 1.0;
        }
        else{
            m = (double(y2 - y1)/(double(x2 - x1)));
        }

        if( ((m>0.45) && (m<0.75)) || ((m<-0.45) && (m>-0.75)) ){

            // If the slope is between measured parameters add to roadLines sequence for further analysis
            cvSeqPush(roadLines, line);
        }
    }

    // otherRoadLine used for comparison
    CvPoint* otherRoadLine;

    for(int a=0; a<roadLines->total; a++){

        CvPoint* roadLine = (CvPoint*)cvGetSeqElem(roadLines,a);
        CvPoint rl1 = roadLine[0];
        CvPoint rl2 = roadLine[1];
        int lineCount = 0;

        if(a>0){

            // Test the current line against all the previous lines in the sequence.
            // If the current line is far enough away from all other lines then draw it
            for(int b=0; b<a; b++){
                otherRoadLine = (CvPoint*)cvGetSeqElem(roadLines,b);
                if((roadLine->x > ((otherRoadLine->x) + 200)) || (roadLine->x < ((otherRoadLine->x) - 200)) ){
                    lineCount++;
                }
            }
            if(lineCount == a){
                cvLine(img_final, roadLine[0], roadLine[1], CV_RGB(0,0,255), 3, CV_AA, 0 );
                RoadLine myLine = RoadLine(roadLine, 1);
                roadVector->push_back(myLine); //ERROR OCCURS HERE
                cvShowImage("Plate Detection", img_final);
                cvWaitKey(0);
            }
        }
        else{
            cvLine(img_final, roadLine[0], roadLine[1], CV_RGB(0,0,255), 3, CV_AA, 0 );
            RoadLine myLine = RoadLine(roadLine, 1);
            roadVector->push_back(myLine //ERROR OCCURS HERE
            cvShowImage("Plate Detection", img_final);
            cvWaitKey(0);
        }
    }

    if(roadVector->size() >= 2){
        int pos = 0;
        RoadLine line1 = roadVector->at(pos);
        RoadLine line2 = roadVector->at(pos + 1);

        CvPoint* A = line1.line;
        CvPoint p1 = A[0];
        CvPoint p2 = A[1];

        int A1 = p1.y - p2.y;
        int B1 = p1.x - p2.x;
        int C1 = (p1.x*p2.y) - (p1.y*p2.x);

        CvPoint* B = line2.line;
        CvPoint p3 = B[0];
        CvPoint p4 = B[1];

        int A2 = p3.y - p4.y;
        int B2 = p3.x - p4.x;
        int C2 = (p3.x*p4.y) - (p3.y*p4.x);

        int det = A2*B1 - A1*B2;

        if(det == 0){
            printf("Lines are parallel");
        }
        else{
            int x = ( C1*(p3.x - p4.x) - (p1.x - p2.x)*C2 )/det;
            int y = ( C1*(p3.y - p4.y) - (p1.y - p2.y)*C2 )/det;

            poi.x = x;
            poi.y = y;

            horizon = poi.x;

            cvCircle(img_final, poi, 10, CV_RGB(255, 0, 0), 2, CV_AA, 0);
        }
    }

    cvShowImage("Plate Detection", img_final);
    cvWaitKey(0);

    return roadVector;
}

Пользовательский класс RoadLine можно увидеть здесь

    #include <cv.h>
class RoadLine{
private:
CvPoint* line;
int lane;
public:
RoadLine(CvPoint*, int);
};
RoadLine::RoadLine(CvPoint* aLine, int aLane){
line = aLine;
lane = aLane;
}

Из отладки я вижу, что "std :: vector * roadVector" правильно инициализируется.

Вот что Eclipse говорит мне:

3 std::vector<RoadLine, std::allocator<RoadLine> >::push_back() F:\MinGW\include\c++\3.4.5\bits\stl_vector.h:560 0x0043e3f9

4 void std::_Construct<RoadLine, RoadLine>() F:\MinGW\include\c++\3.4.5\bits\stl_construct.h:81 0x0044015d  

И программа переходит к этому фрагменту кода в stl_construct.h

  template<typename _T1, typename _T2>
inline void
_Construct(_T1* __p, const _T2& __value)
{
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 402. wrong new expression in [some_]allocator::construct
  ::new(static_cast<void*>(__p)) _T1(__value); //DEBUG THROWS ME TO THIS LINE
}

Опять же, любая помощь будет принята с благодарностью.

Приветствия

1022 * Пат *

Ответы [ 7 ]

4 голосов
/ 28 марта 2009

Вы используете не вектор указателей, а вектор объектов. В этом случае ваш класс должен иметь конструктор копирования, так как push_back хранит копию объекта.

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

2 голосов
/ 28 марта 2009

Ваш новый класс RoadLine обязательно приведет к катастрофе:

RoadLine::RoadLine(CvPoint* aLine, int aLane){
    line = aLine;
    lane = aLane;
}

RoadLine::RoadLine(const RoadLine & myRoadLine){
    line = myRoadLine.line;
    lane = 1;
}

RoadLine::~RoadLine(){
    delete line;
}

код, использующий его:

                        if(lineCount == a){
                                cvLine(img_final, roadLine[0], roadLine[1], CV_RGB(0,0,255), 3, CV_AA, 0 );
                                RoadLine myLine = RoadLine(roadLine, 1);//create object on the Stack
                                roadVector->push_back(myLine); //Push COPY of myLine
                                cvShowImage("Plate Detection", img_final);
                                cvWaitKey(0);
                        }//Stack-based object "myLine" is automatically destroyed here (leaves scope)

автоматическое уничтожение «myLine» удалит «myLine.line» (в dtor RoadLine) но «myLine.line» все еще ссылается в векторе (вы только что нажали его).

Вы должны либо сделать ГЛУБОКУЮ КОПИЮ строки (как предлагали другие), что-то вроде этого:

RoadLine::RoadLine(const RoadLine & myRoadLine){
    line = new CvPoint(*myRoadLine.line);//assuming CvPoint can be copy-constructed
    lane = 1;
}

Или используйте объект CvLine вместо указателя (или что-то еще, нужно больше контекста)

РЕДАКТИРОВАТЬ: В copy-ctor Дирка Джентли есть ошибка, потому что она утекает в память бывшему «строковому» члену должно быть:

RoadLine& operator=(const RoadLine & o){
     if (this != &o) { //Remember to check for self-assignment.
      delete []line;//delete[] vs. delete !
      line = 0;//if next line throws at least we won't double-delete line
      line = new CvPoint[ 2 ]; //this might throw ! should catch (or redesign to get rid of new (prefered)
      line[ 0 ] = o.line[ 0 ];
      line[ 1 ] = o.line[ 1 ];
      lane = o.lane;
     }
     return *this;
}
//consistent constructor !
RoadLine::RoadLine(CvPoint* aLine, int aLane)
    :line(new CvPoint[2]),//might throw, but its better to throw in initializer ! (if you just have one pointer it might be ok to do it like this)
    lane(aLane)
{
     line[0] = aLine[0];
     line[1] = aLine[1];
}
RoadLine::~RoadLine(){
    delete[] line;//also use delete[] vs. normal delete here !
}

РЕДАКТИРОВАТЬ 2: Я почти забыл, что у меня была идея, почему она падает! может быть, вы пытаетесь построить пару с последним и последним +1 CvPoint (как этот явно ложный код)?

CvPoint Pnts[2] = {CvPoint(0,0),CvPoint(1,1)};
Roadline Line(&Pnts[1],1);//tries to access Pnts[2] which is one past end !
1 голос
/ 30 марта 2009

У вас нет вектора указателей.

std::vector<RoadLine>* roadVector

- указатель на вектор объектов RoadLine. Если вам нужен вектор указателей, вы должны сделать:

std::vector<RoadLine*> roadVector

Это может помочь вам (поскольку вектор больше не будет вызывать конструкторы копирования), но вы все равно должны смотреть на их сортировку, как предлагали другие.

1 голос
/ 29 марта 2009

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

Если вы добавляете деструктор, тогда вам НУЖЕН конструктор копирования и оператор присваивания. Без исключений. Даже если вы не собираетесь копировать объект, вы все равно должны объявить его в приватном разделе, чтобы компилятор выдавал ошибки, если они используются случайно.

Вы также должны использовать указатель с подсчетом ссылок вместо необработанного указателя в стиле C всякий раз, когда контролируется время жизни объекта (в C ++ - скажем, это «RAII»). Если вы сделаете это, деструктор исчезнет с RoadLine, и, как ни странно, ваша проблема исчезнет.

1 голос
/ 28 марта 2009

Вашему классу RoadLine не хватает надлежащего копиратора. Теперь, поскольку у вас есть член, который указывает на объект CvPoint, вы создаете копию указателя каждый раз, когда вы push_back. Это, вероятно, не желательно.

RoadLine::RoadLine(const RoadLine & o){
     line = new CvPoint[ 2 ]; 
     line[ 0 ] = o.line[ 0 ];
     line[ 1 ] = o.line[ 1 ];
     lane = o.lane;
}

RoadLine& operator=(const RoadLine & o){
     if (this != &o) { //Remember to check for self-assignment.
      line = new CvPoint[ 2 ]; 
      line[ 0 ] = o.line[ 0 ];
      line[ 1 ] = o.line[ 1 ];
      lane = o.lane;
     }
     return *this;
}

Сократите код: попробуйте выделить проблему:

int main() {
    CvPoint pa[] = { CvPoint(0, 0), CvPoint(100, 100) };
    RoadLine rl1(pa, 1);

    vector<RoadLine> v;
    v.push_back(rl1);

    return 0;
}

Это сбой?

0 голосов
/ 28 марта 2009

Я изменил определение класса RoadLine на:

#include <cv.h>

class RoadLine{

private:
    int lane;
public:
    CvPoint* line;
    RoadLine(CvPoint*, int);
    RoadLine(const RoadLine &);
    ~RoadLine();
    RoadLine& operator=(const RoadLine & o);
};

RoadLine::RoadLine(CvPoint* aLine, int aLane){
    line = aLine;
    lane = aLane;
}

RoadLine::RoadLine(const RoadLine & myRoadLine){
    line = new CvPoint[ 2 ]; // CRASHES HERE
    line[ 0 ] = myRoadLine.line[ 0 ];
    line[ 1 ] = myRoadLine.line[ 1 ];
    //line = new CvPoint(*myRoadLine.line);
    lane = myRoadLine.lane;
}

RoadLine::~RoadLine(){
    delete line;
}

RoadLine& RoadLine::operator=(const RoadLine & o){
     if (this != &o) { //Remember to check for self-assignment.
      line = new CvPoint[ 2 ];
      line[ 0 ] = o.line[ 0 ];
      line[ 1 ] = o.line[ 1 ];
      lane = o.lane;
     }
     return *this;
}

Это текущая версия класса RoadLine

Вот как я реализую класс:

else{
        cvLine(img_final, roadLine[0], roadLine[1], CV_RGB(0,0,255), 3, CV_AA, 0 );
        RoadLine myLine(roadLine, 1);
        roadVector->push_back(myLine); // FROM HERE
        cvShowImage("Plate Detection", img_final);
        cvWaitKey(0);
}

Когда вызывается push_back, он вызывает конструктор копирования, но программа падает там, где выделено выше

Какая разница из-за того, что мой вектор определен;

std::vector<RoadLine>* roadVector

и что у меня есть CvPoint *, а не CvPoint []

извините, если эти вопросы кажутся очень простыми

0 голосов
/ 28 марта 2009

Такие ошибки обычно возникают из-за неправильного управления памятью. К сожалению, вы не опубликовали способ управления памятью.

Если вы можете запустить его в системе Linux, вы можете попробовать запустить свою программу под valgrind, что помогает отследить неправильный доступ к памяти / освобождение. К сожалению, valgrind недоступен под окнами, но могут быть заменители.

...