2009-03-28 18 views
0

Ich habe ziemlich viel Mühe mit dem Versuch, ein Objekt meiner benutzerdefinierten Klasse zu einem Vektor von Zeigern mit meiner benutzerdefinierten Klasse push_back als Typ. Bitte beachten Sie den folgenden Code zusammen mit dem Fehler erhalten. Ich benutze Eclipse mit dem CDT-Plugin und OpenCV unter Windows XP.Vektor von Zeigern Problem

Ich habe so viel Zeit damit verbracht, eine Antwort zu finden, aber ohne Erfolg! PS Ich bin ein Student und Zeiger usw. sind nicht mein Ding!

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; 
} 

Die benutzerdefinierte Klasse kann 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; 
} 

ich sehen kann Von Debuggen hier gesehen werden, dass "std :: vector < Roadline> * roadVector" richtig intialised wird. Hier

ist das, was von Eclipse sagt mir:

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 

und das Programm springt zu diesem Abschnitt des Codes in 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 
} 

Wieder jede Hilfe sehr geschätzt würde.

Prost

Pat

+0

BTW, wenn Sie Zeiger nicht zu viel mögen, möchten Sie vielleicht mehr über Referenzen in C++ lesen und sie verwenden. Es ist eine gute Möglichkeit, einige Zeiger zu beseitigen. Zum Beispiel gibt es wirklich keinen Grund, den street_vector als Zeiger auf einen Vektor statt nur als Vektorref zu übergeben. – Uri

Antwort

1

Ihre RoadLine Klasse fehlt eine richtige Kopie-Ctor. Jetzt, da Sie ein Mitglied haben, das auf ein CvPoint Objekt zeigt, müssen Sie eine Kopie des Zeigers jedes Mal erstellen, wenn Sie push_back. Dies ist wahrscheinlich nicht wünschenswert.

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; 
} 

Code Kürzen: Versuchen Sie, das Problem zu isolieren:

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

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

    return 0; 
} 

Ist dieser Absturz?

+0

Ich muss an meiner Tippgeschwindigkeit arbeiten :) – ya23

+0

Eigentlich ist die Kopie-Ctor in Ordnung, und Ihre Version würde nur verschlechtern, weil Zeile ein Array ist, nicht ein CvPoint – jpalecek

+0

@jpalecek: Das war Beispielcode. Aber ich verstehe deinen Standpunkt. Habe 'CvPoint *' nicht im Detail angeschaut. – dirkgently

4

Sie verwenden keinen Vektor von Zeigern, sondern Vektor von Objekten. In diesem Fall muss Ihre Klasse einen Kopierkonstruktor haben, da push_back eine Kopie des Objekts speichert.

Als allgemeine Fehlerbehebungsempfehlung versuchen Sie, das Problem zu beheben, indem Sie so viel Code wie möglich entfernen und trotzdem ein falsches Verhalten sehen. Versuchen Sie das einfachste Beispiel zu finden, das fehlschlägt.

0

Diese Art von Fehlern wird normalerweise durch inkorrekte Speicherverwaltung verursacht. Leider hast du die Art und Weise, wie du dein Gedächtnis verwaltest, nicht gepostet.

Wenn Sie es auf einem Linux-System ausführen können, können Sie versuchen, Ihr Programm unter valgrind auszuführen, was dabei hilft, falsche Speicherzugriffe/-befreiungen aufzuspüren. Leider ist Valgrind unter Windows nicht verfügbar, aber es kann Ersatz geben.

0

Ich habe meine Klassendefinition von Roadline geändert: Dies ist die aktuelle Version der Roadline Klasse

#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; 
} 

Dies ist, wie ich die Klasse bin der Umsetzung:

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); 
} 

wenn push_back aufgerufen wird es ruft die Copykonstruktor aber das Programm stürzt ab, wo oben

hervorgehoben

Welchen Unterschied macht die Tatsache, dass mein Vektor definiert ist?

std::vector<RoadLine>* roadVector 

und ich habe einen CvPoint * nicht CvPoint []

leid, wenn diese scheinen sehr grundlegende Fragen

2

Ihre neue Roadline-Klasse wird sicherlich zu einer Katastrophe führen:

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

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

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

Code es:

     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) 

die automatische Vernichtung von „Myline“ löscht „myLine.line“ (in Roadline des dtor) aber „myLine.line“ ist nach wie vor in dem Vektor verwiesen (die Sie gerade gedrückt).

Sie müssen entweder eine tiefe Kopie der Linie machen (wie andere vorgeschlagen), etwa so:

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

Oder ein CvLine Objekt verwenden, anstatt ein Zeiger (oder etwas anderes, mehr Kontext benötigen)

EDIT: Dirk leicht copy-ctorhas einen Fehler, weil es sein Gedächtnis auf die ehemalige "Linie" -Mitglied Lecks sollten:

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 ! 
} 

EDIT 2: Ich hätte fast vergessen, dass ich eine Idee hatte, warum es abstürzt! Vielleicht versuchst du ein Paar mit dem letzten und letzten + 1 CvPoint zu bauen (wie dieser offensichtlich falsche Code)?

CvPoint Pnts[2] = {CvPoint(0,0),CvPoint(1,1)}; 
Roadline Line(&Pnts[1],1);//tries to access Pnts[2] which is one past end ! 
+0

Hallo qwerty, Danke für deine Hilfe. Ich habe eine kurze Frage zu Ihrer Antwort. Willst du sagen, dass ich nur die Kopie const ändern muss? Oder muss ich ändern, wie der Code implementiert wird? Auch in der Kopie cont Zeile ist vom Typ CvPoint * also sollte diese Zeile etwas wie lesen: –

+0

line = new CvPoint * (* myRoadLine.line); –

+0

Entschuldigung ich sehe jetzt, wie Linie = neuer CvPoint (* myRoadLine.line); ist korrekt. Ich bin mir immer noch nicht sicher, wie es benutzt wird. danke nochmal –

1

Der Trick mit C++ ist es, die „~“ Schlüssel so groß und rot, sich vorzustellen, und dass die Alarmglocken klingen, wenn sie gedrückt wird, dh. wann immer Sie daran denken, einer Klasse einen Destruktor hinzuzufügen.

Wenn Sie eine destructor sind das Hinzufügen, dann müssen Sie einen Kopierkonstruktor und Zuweisungsoperator. Keine Ausnahmen. Selbst wenn Sie das Objekt nicht kopieren, sollten Sie es dennoch im privaten Bereich deklarieren, so dass der Compiler Fehler gibt, wenn sie versehentlich verwendet werden.

Sie sollten auch einen Verweis gezählten Zeiger anstelle eines rohen C-style-Zeigers verwenden, wann immer die Lebensdauer eines Objekts gesteuert wird (in C++ - sprechen Sie das ist "RAII"). Wenn du das tust, würde der Destruktor von RoadLine verschwinden, und das mag dein Problem auch magisch sein.

1

Sie haben noch einen Vektor von Zeigern.

std::vector<RoadLine>* roadVector 

ist ein Zeiger auf einen Vektor von RoadLine-Objekten. Wenn Sie einen Vektor von Zeigern wollen, sollten Sie tun:

std::vector<RoadLine*> roadVector 

die Ihnen helfen können (da der Vektor wird Kopierkonstruktoren nicht mehr sein Aufruf), aber Sie sollten immer noch diejenigen aus, wie andere bei Sortierung suchen müssen empfohlen.