C ++指针问题

时间:2010-09-24 17:57:22

标签: c++ pointers

我道歉,因为这是一个相当棘手的问题,但我无法弄明白这一点。

class View //simplified
{
public:
  ROILine* ROI() {return _roi;} //setter does some control stuff...
private:
  ROILine *_roi;
}

class ROI : public eq::Object
{

public:
    //virtual ROI(ROI* copy) = 0;
    virtual ~ROI() {};

    virtual uint32_t getType() = 0;

    virtual void reset() = 0;

    virtual bool addPoint( eq::Vector3f point ) = 0;
    virtual bool previewPoint( eq::Vector3f point ) = 0;

    virtual bool getNotationLocation( eq::Vector3f& point ) = 0;

    virtual bool draw() = 0;

protected:

    enum ROIType {
        NONE = 0,
        LINE,
        POLY,
        AREA,
        VOLUME
    };

    enum ROIMeasure {
        RM_LENGTH = 1,
        RM_AREA,
        RM_VOLUME,
    };

private:

};


class ROILine : virtual public ROI
{

public:
    ROILine();
    ROILine(ROILine* copy);
    ROILine(const ROILine& copy);
    virtual ~ROILine() {SFLog(@"Destroying ROILine: 0x%x",this);};
    void reset();

    float distance() { return _start.distance(_end); }


    // ROI Interface
    uint32_t getType() { return ROI::LINE; }
    virtual bool draw();
    bool addPoint( eq::Vector3f point );
    bool previewPoint( eq::Vector3f point );
    bool getNotationLocation( eq::Vector3f& point );

    eq::net::DataOStream& serialize(eq::net::DataOStream& os) ;
    eq::net::DataIStream& deserialize(eq::net::DataIStream& is) ;

protected:

    enum ROILineState { // RLS_
        RLS_RESET,
        RLS_START,
        RLS_PREVIEW,
        RLS_END,
    };

private:
    uint32_t _state;
    eq::Vector3f _start;
    eq::Vector3f _end;
};

ROILine::ROILine(const ROILine& copy) : ROI()
{
    reset();
    switch (copy._state) 
    {
        case RLS_PREVIEW:
        case RLS_END:
            addPoint(eq::Vector3f(copy._start));
            addPoint(eq::Vector3f(copy._end));
            break;
        case RLS_START:
            addPoint(eq::Vector3f(copy._start));
            break;
        case RLS_RESET:
        default:
            break;
    }
}

/*!
 @abstract resets the line values and state
 */
void ROILine::reset()
{
    _state = RLS_RESET;
    _end = eq::Vector3f::ZERO;
    _start = eq::Vector3f::ZERO;
}
/*!
 @abstract if it has 2 points, draw the line. (_state > _PREVIEW)
 @discussion assumes GL is already set up.  Executes drawing commands.
 @result true if the line was drawn
 */
bool ROILine::draw()
{
    bool retVal = false;

    if (_state >= RLS_PREVIEW) {
        //glTranslatef(0.0f, 0.0f, -1.0f); //Back Up?
        glColor3f( 1.0f, 0.0f, 0.0f );  //Red
        glEnable( GL_LINE_SMOOTH );
        glLineWidth( 1 );
        glBegin( GL_LINES );
        {
            glVertex3fv( _start.array );
            glVertex3fv( _end.array );
        }
        glEnd();    
        //glTranslatef(0.0f, 0.0f, 1.0f); // Return
        retVal =  true;
    } 

    return retVal;

}

// Elsewhere...

View *v = getView(); // returns the view object

// Destroys each time, but works wonderfully
ROILine r = ROILine(*(v->ROI()));
r.draw();

// Does not work (EXC_BAD_ACCESS)
v->ROI()->draw();

// Does not work (EXC_BAD_ACCESS on draw());
ROILine *r = v->ROI();
r->draw(); // debug shows r != 0x0

当我打破r->draw()并继续时,我得到的错误如下。

[Switching to process 12453]
Current language:  auto; currently objective-c++
Warning: the current language does not match this frame.
(gdb) continue 
Program received signal:  “EXC_BAD_ACCESS”.

"EXC_BAD_ACCESS"发生r->draw()v->ROI()->draw()它根本没有进入程序,只是暂停而bt给了我?? < / p>

我的拷贝构造函数工作,因为draw()函数实际上绘制了它应该的位置(而不是!! @#$!4!#@ land)我不知道的是,为什么复制值有效,但是访问v->ROI()->draw()没有。 必须才能v->ROI()才能制作副本!!

是? ......不是吗?

很困惑......

谢谢,

5 个答案:

答案 0 :(得分:1)

我觉得有些奇怪的事情发生了。

你说包含这一行的代码非常有效:

 ROILine r = ROILine(*(v->ROI()));

在此行中,您已成功执行*(v->ROI())

但是你说如果你尝试做ROILine *r = v->ROI()那么r的值是NULL。

我认为这些都不是真的(因为这意味着你已成功解除引用NULL指针)。我可以想到两个原因:

  1. 按顺序调用它们不起作用。如果你将“奇妙地工作”块移到其他块之下,它会失败吗?如果是这样,您可能正在复制指针并销毁它或它引用的数据。然后,数据无法访问。
  2. 未正确设置或初始化View类的私有ROILine *成员。有时,这会导致奇怪的随机行为;一个编译版本(具有“作品奇妙地块”)可以随机地将该成员初始化为非零值,而另一个编译版本(具有一个失败块)可以随机地将该成员初始化为零。我听说这被称为“Heisenbug”,因为尝试打印调试信息可能会改变问题。

此外,确保在执行行设置后验证r为NULL 。有些编译器将指针初始化为NULL,但可能尚未设置。还要检查以确保已关闭优化;有时调试器不能很好地进行优化,这可以使你在认为执行完代码后执行一行代码。

答案 1 :(得分:1)

这些症状听起来像你的ROILine对象已被删除,让你留下一个指向释放内存的悬空指针。当您尝试调用虚函数时,它会崩溃,因为vtable已被覆盖,但是当您使用复制构造函数创建副本时,它至少从释放的对象获取一些有效数据,并且似乎有效。

答案 2 :(得分:1)

假设ROILine的复制构造函数中的所有内容都正常工作,那么这里有可能:某些东西覆盖了ROILine返回的View::ROI()实例的几个字节。

最有可能的是,ROILine对象的前几个字节包含指向该类的虚函数表的指针。 (至少这是典型的C ++实现所做的。)如果这些字节被覆盖,而不是通过虚函数表调用,程序将最终通过垃圾调用,几乎肯定会崩溃。

但是,在通过复制构造函数创建对象的副本时,根本不会访问指向虚函数表的指针(除非您在复制构造函数中调用虚函数)。在这种情况下,所有数据都会成功复制到具有正确vtable指针的新对象。

由于draw是vritual,这可以解释为什么在副本上调用它时在原件上调用它不起作用。

如果发生了这种情况,那么您需要弄清楚覆盖ROILine实例的部分内容。如果该实例是另一个对象的一部分,那么它可能很容易。如果该实例已经单独分配了堆,那么可能会有点困难。

答案 3 :(得分:0)

我认为ROILine应该继承ROI。 在ROILine中绘制虚拟,然后

ROILine * r = v-&gt; ROI(); R-&GT;绘制(); // debug显示r!= 0x0

应该有用......

连接到问题(或不是)调用返回ROI的函数与ROI构造函数完全相同是不好的做法。

(指:ROILine * ROI(){return _roi;} // setter做一些控件......)

也许编译器感到困惑......

答案 4 :(得分:0)

您的复制构造函数在引用时起作用,为此,您需要为其提供一个取消引用(可能为空)的指针。这是语言中有趣的东西之一,因为对引用指针的引用实际上不会取消引用指针,直到你使用引用(C ++真的是多范式,它甚至是懒惰的!)。由于这是未定义的行为,因此只有复制构造函数才有可能。可能在视图中你以某种方式使指针无效。

#include <iostream>

using namespace std;

int addOne(int const & n) {
    return n + 1; // Uh oh.
}

int main() {
    int * ptr = 0;
    cout << addOne(*ptr) << endl; // Doesn't crash here.
    return 0;
}