指针问题向量

Posted

技术标签:

【中文标题】指针问题向量【英文标题】:Vector of pointers problem 【发布时间】:2010-10-16 02:53:01 【问题描述】:

我在尝试将自定义类的对象 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 * 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

再次感谢任何帮助。

干杯

拍拍

【问题讨论】:

顺便说一句,如果您不太喜欢指针,您可能需要考虑阅读更多关于 C++ 中的引用并使用它们的信息。这是消除一些指针的好方法。例如,实际上没有理由将 road_vector 作为指向向量的指针传递,而不仅仅是作为向量引用。 【参考方案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;

这会崩溃吗?

【讨论】:

其实copy-ctor是可以的,你的版本只会更糟,因为line是一个数组,而不是一个CvPoint @jpalecek:那是示例代码。但我明白你的意思。还没仔细看CvPoint * 嗨,所以一旦我复制了 roadVector,我应该在副本上调用 push_back 吗?例如:roadVectorCopy->push_back(myLine); ??? @Pat Rohan:push_back 制作了一份副本,并将其存储在向量中。确保你的班级有一个合适的 copy-ctor。语义将取决于您想要什么。 @dirkgently:在高层次上,我想返回 roadVector,然后在另一个函数中修改 ite 对象。我知道通过引用传递是做到这一点的方法。我试图展示我的新 RoadLine 类,但它没有格式化。但是无论如何我都会发布它。感谢您迄今为止的帮助【参考方案2】:

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

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

【讨论】:

【参考方案3】:

这些类型的错误通常是由不正确的内存管理引起的。遗憾的是,您还没有发布管理记忆的方式。

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

【讨论】:

【参考方案4】:

我已将 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[]

对不起,如果这些问题看起来很基本

【讨论】:

【参考方案5】:

您的新 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”(您刚刚推送了它)。

您必须对行进行深度复制(如其他人建议的那样),如下所示:

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

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

编辑: Dirk Gently 的 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:我几乎忘记了我知道它为什么会崩溃!也许您尝试使用 last 和 last+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 !

【讨论】:

嗨,qwerty,感谢您的帮助。关于你的回答,我有一个简短的问题。你是说我只需要改变copy const吗?还是我需要更改代码的实现方式?在复制 cont 行中也是 CvPoint* 类型,所以该行应该是这样的: line = new CvPoint*(*myRoadLine.line); 对不起,我现在看到 line = new CvPoint(*myRoadLine.line); 是正确的。但是我仍然不确定它是如何使用的。再次感谢 CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);我们需要有关此功能的更多信息。我猜它只是返回一个指向更大数组的一部分的指针? (这将改变整个“所有权”场景) 是的,序列本质上是一个向量,无论如何,据我所知。索引 i=0 处的行地址为 0x012f8858,序列行的地址为 0x012f8808。所以它似乎确实返回了一个指向更大序列的指针【参考方案6】:

C++ 的诀窍是把“~”键想象成又大又红,只要你按下它就会响起警铃,即。每当您考虑向类添加析构函数时。

如果要添加析构函数,则需要复制构造函数和赋值运算符。没有例外。即使您不打算复制该对象,您仍然应该在私有部分中声明它们,这样如果不小心使用它们,编译器就会报错。

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

【讨论】:

【参考方案7】:

你没有指针向量。

std::vector<RoadLine>* roadVector

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

std::vector<RoadLine*> roadVector

这可能对您有所帮助(因为向量将不再调用复制构造函数),但您仍然应该按照其他人的建议将它们整理出来。

【讨论】:

以上是关于指针问题向量的主要内容,如果未能解决你的问题,请参考以下文章

将指针向量元素推回非指针向量c ++时出错

将指向向量向量的指针移动到特定位置

当向量在内部类中时,如何删除指向对象的向量指针

创建字符指针向量以指向字符串向量

从类指针向量创建成员变量向量

如何创建指向向量的指针向量