指针问题传染媒介

时间:2009-03-28 13:33:53

标签: c++ pointers vector opencv segmentation-fault

我尝试将自定义类的对象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&lt; RoadLine&gt; * 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
}

再次感谢任何帮助。

干杯

专利

7 个答案:

答案 0 :(得分:4)

您不使用指针向量,而是使用对象向量。在这种情况下,您的类需要一个复制构造函数,因为push_back存储了一个对象的副本。

作为一般调试建议,尝试通过删除尽可能多的代码并仍然看到不正确的行为来解决问题。尝试找到失败的最简单的例子。

答案 1 :(得分: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 of line(正如其他人建议的那样),如下所示:

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

或者使用CvLine对象而不是指针(或其他东西,需要更多上下文)

编辑: Dirk Gently的副本有一个bug,因为它会将内存泄漏给前“行”成员 应该是:

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 !

答案 2 :(得分:1)

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

这会崩溃吗?

答案 3 :(得分:1)

使用C ++的诀窍是将“〜”键想象为大号和红色,并且只要按下它就会发出警报声,即。每当你想要在类中添加析构函数时。

如果你要添加一个析构函数,那么你需要一个复制构造函数和赋值运算符。没有例外。即使您不打算复制该对象,您仍应在私有部分声明它们,以便编译器在意外使用时会出错。

每当控制对象的生命周期时,你也应该使用引用计数指针而不是原始的C风格指针(在C ++中 - 说这是“RAII”)。如果你这样做,析构函数将从RoadLine中消失,而且,神奇地,你的问题也会消失。

答案 4 :(得分:1)

你没有指针向量。

std::vector<RoadLine>* roadVector

是指向RoadLine对象矢量的指针。如果你想要一个指针矢量,你应该这样做:

std::vector<RoadLine*> roadVector

这可能对你有帮助(因为向量不会再调用复制构造函数),但是你仍然应该像其他人所建议的那样对它们进行排序。

答案 5 :(得分:0)

这些错误通常是由错误的内存管理引起的。可悲的是,你还没有发布如何管理记忆的方式。

如果你可以在linux系统上运行它,你可以尝试在valgrind下运行你的程序,这有助于追踪不正确的内存访问/释放。不幸的是,valgrind在windows下不可用,但可能有替代品。

答案 6 :(得分: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 []

对不起,如果这些似乎是非常基本的问题