指针问题向量
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
这是 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
这可能对您有所帮助(因为向量将不再调用复制构造函数),但您仍然应该按照其他人的建议将它们整理出来。
【讨论】:
以上是关于指针问题向量的主要内容,如果未能解决你的问题,请参考以下文章