0

カスタム クラスのオブジェクトを、カスタム クラスを型として持つポインタのベクトルに push_back しようとすると、かなりの問題が発生します。以下のコードと、受け取ったエラーを参照してください。Windows XPでCDTプラグインとOpenCVでEclipseを使用しています。

私は答えを見つけるために多くの時間を費やしましたが、役に立ちませんでした! 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 <RoadLine>* 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
}

繰り返しますが、どんな助けでも大歓迎です。

乾杯

パット

4

7 に答える 7

4

ポインターのベクトルではなく、オブジェクトのベクトルを使用します。その場合、push_back はオブジェクトのコピーを格納するため、クラスにはコピー コンストラクターが必要です。

一般的なデバッグのアドバイスとして、できるだけ多くのコードを削除して問題を煮詰めてみてください。それでも正しくない動作が見られます。失敗する最も単純な例を見つけてみてください。

于 2009-03-28T13:40:56.803 に答える
2

あなたの新しい 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」(RoadLine の dtor 内) が削除されますが、「myLine.line」はベクター内で参照されたままです (プッシュしただけです)。

次のような行のDEEP COPYを作成する必要があります(他の人が提案したように):

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

または、ポインターではなく CvLine オブジェクトを使用します (または、他の何か、より多くのコンテキストが必要です)

編集: Dirk Gently の copy-ctorhas にはバグがあります。以前の「行」メンバーにメモリがリークするためです。

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: クラッシュする理由がわかったのをほとんど忘れていました! おそらく、最後と最後+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 !
于 2009-03-28T17:28:24.260 に答える
1

C++ の秘訣は、"~" キーが大きくて赤いもので、押すたびにアラーム ベルが鳴ると想像することです。クラスにデストラクタを追加することを考えているときはいつでも。

デストラクタを追加する場合は、コピー コンストラクタと代入演算子が必要です。例外なく。オブジェクトをコピーしない場合でも、private セクションで宣言する必要があります。これにより、それらが誤って使用された場合にコンパイラがエラーを出します。

また、オブジェクトの有効期間が制御されている場合は常に、生の C スタイル ポインターの代わりに参照カウント ポインターを使用する必要があります (C++ で言えば、これは "RAII" です)。これを行うと、デストラクタは RoadLine から消え、魔法のように問題も消えます。

于 2009-03-29T19:21:23.653 に答える
1

あなたのRoadLineクラスには適切な copy-ctor がありません。ここで、オブジェクトを指すメンバーがある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;
}

これはクラッシュしますか?

于 2009-03-28T13:37:37.233 に答える
1

ポインターのベクトルがありません。

std::vector<RoadLine>* roadVector

RoadLine オブジェクトのベクトルへのポインタです。ポインターのベクトルが必要な場合は、次のようにする必要があります。

std::vector<RoadLine*> roadVector

それはあなたを助けるかもしれませんが(ベクターはコピーコンストラクターを呼び出さないため)、他の人が提案したようにそれらを整理することを検討する必要があります.

于 2009-03-29T20:50:43.673 に答える
0

これらの種類のエラーは通常、不適切なメモリ管理が原因で発生します。悲しいことに、あなたはあなたの記憶をどのように管理するかについて投稿していません。

Linuxシステムで実行できる場合は、valgrindでプログラムを実行してみてください。これは、誤ったメモリアクセス/解放を追跡するのに役立ちます。残念ながら、valgrindは窓の下では利用できませんが、代わりになる可能性があります。

于 2009-03-28T13:58:49.273 に答える
0

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 *を持っています

これらが非常に基本的な質問のように思われる場合は申し訳ありません

于 2009-03-28T16:53:47.963 に答える