代码之家  ›  专栏  ›  技术社区  ›  Stephen Furlani

C++指针问题

  •  -4
  • Stephen Furlani  · 技术社区  · 14 年前

    我很抱歉,因为这是一个不太好的问题,但我想不出这一个。

    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->绘制() v->ROI()->draw() 它根本就没有进入程序,只是停下来 bt 给我一个 ??

    我的复制构造函数可以工作,因为draw()函数实际上在它应该绘制的位置(而不是!啊!4!#@土地)我不理解的是,为什么复制价值是有效的,但是访问 v->ROI()->绘制()) 没有。它 必须 v->ROI() 为了复制!!

    对?…不?

    如此困惑…

    谢谢,

    5 回复  |  直到 14 年前
        1
  •  1
  •   TheUndeadFish    14 年前

    假设复制构造函数中的所有内容 ROILine 是否正常工作,则有一种可能:某些内容覆盖了 旋转线 实例返回者 View::ROI() .

    最有可能的是 旋转线 对象包含指向该类的虚拟函数表的指针。(至少这就是典型的C++实现。)如果这些字节被重写,而不是通过虚函数表调用,程序将最终通过垃圾调用,并且几乎肯定会崩溃。

    但是,通过复制构造函数复制对象时,可能根本无法访问指向虚拟函数表的指针(除非要在复制构造函数中调用虚拟函数)。在这种情况下,所有数据都将成功复制到具有正确vtable指针的新对象。

    自从 draw 是虚拟的,这可以解释为什么在副本上调用它有效,而在原件上调用它却无效。

    如果这是正在发生的,那么您需要找出覆盖您的 旋转线 实例。如果该实例是另一个对象的一部分,那么可能很容易。如果该实例是单独堆分配的,那么它可能会更难一些。

        2
  •  1
  •   user    14 年前

    我觉得有点奇怪。

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

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

    在这一行你表演 *(v->ROI()) 成功。

    但你说过如果你想这么做 ROILine *r = v->ROI() 则r的值为空。

    我不认为这两者都是真的(因为这意味着你已经成功地取消了空指针的引用)。我可以想到两个原因:

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

    另外,确保您已验证r为空 之后 将执行设置其值的行。有些编译器初始化指向空的指针,但可能尚未设置。还要检查以确保您关闭了优化;有时调试器不能很好地处理优化,这会使一行代码在您认为已执行之后执行。

        3
  •  1
  •   Chris Dodd    14 年前

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

        4
  •  0
  •   Boaz    14 年前

    我认为Roiline应该从ROI继承。 在Roiline中进行虚拟绘制,然后

    roiline*r=v->roi(); r->draw();//调试显示r!= 0x0

    应该工作…

    连接到问题上(或者不连接到问题上),调用一个函数来返回与ROI构造函数完全相同的ROI是一个糟糕的实践。

    (参考:roiline*roi()return//setter做一些控制工作…)

    也许编译器会感到困惑…

        5
  •  0
  •   Paul    14 年前

    复制构造函数在引用时工作,要执行此操作,需要向它提供一个未引用(可能为空)的指针。这是语言中有趣的事情之一,因为引用引用的指针实际上不会引用指针,直到使用引用(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;
    }