C ++ Указатель Вопрос - PullRequest
       1

C ++ Указатель Вопрос

0 голосов
/ 24 сентября 2010

Я прошу прощения, потому что это скорее вопрос, но я не могу разобраться в этом.

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 дает мне ??

Мой конструктор копирования работает, потому что функция draw () на самом деле рисует, где должна (вместо !! @ # $! 4! # @ Land). Что я не понимаю, так это то, почему копирование значения работает, доступ v->ROI()->draw() не это ДОЛЖНО иметь v->ROI(), чтобы сделать копию !!

да? ... нет?

так растерялся ...

Спасибо

Ответы [ 5 ]

1 голос
/ 24 сентября 2010

Если предположить, что все в вашем конструкторе копирования для ROILine работает правильно, то есть возможность: что-то перезаписало несколько байтов экземпляра ROILine, возвращенного View::ROI().

Скорее всегопервые несколько байтов объекта ROILine содержат указатель на таблицу виртуальных функций для этого класса.(По крайней мере, это то, что делают типичные реализации C ++.) Если эти байты будут перезаписаны, то вместо вызова через таблицу виртуальных функций программа завершит вызов через мусор и почти наверняка потерпит крах.

Однако, когдаделая копию объекта через конструктор копирования, этот указатель на таблицу виртуальных функций, вероятно, вообще не доступен (если только вы не должны были вызывать виртуальную функцию в конструкторе копирования).В этом случае все данные успешно копируются в новый объект, который имеет правильный указатель виртуальной таблицы.

Поскольку draw является критически важным, это объясняет, почему вызов этой копии работает при вызове ее на оригинале.не.

Если это то, что происходит, тогда вам нужно выяснить, что перезаписывает часть вашего ROILine экземпляра.Если этот экземпляр является частью другого объекта, то это может быть легко.Если этот экземпляр был выделен кучей по отдельности, то это может быть несколько сложнее.

1 голос
/ 24 сентября 2010

Симптомы говорят, что ваш объект ROILine был удален, оставляя вас с висящим указателем на освобожденную память. При попытке вызвать виртуальную функцию происходит сбой, потому что vtable был перезаписан, но когда вы создаете копию с помощью конструктора копирования, он получает по крайней мере некоторые допустимые данные из освобожденного объекта и, похоже, работает.

1 голос
/ 24 сентября 2010

Я думаю, что происходит что-то странное.

Вы сказали, что код, содержащий эту строку, прекрасно работает:

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

В этой строке вы успешно выполните *(v->ROI()).

Но вы сказали, что если вы попытаетесь сделать ROILine *r = v->ROI(), тогда значение r равно NULL.

Я не думаю, что они оба могут быть истинными (потому что это будет означать, что вы успешно разыменовали NULL-указатель). Я могу придумать две причины для этого:

  1. Последовательный вызов их не работает. Если вы переместите блок «работает чудесно» под остальными, он потерпит неудачу? Если это так, возможно, вы копируете указатель и уничтожаете его или данные, на которые он ссылается. Затем, позже, данные не доступны.
  2. Закрытый член ROILine * класса View не установлен или не инициализирован должным образом. Иногда это может привести к странному стохастическому поведению; одна скомпилированная версия (с «блоком чудесных работ») может случайным образом инициализировать этот элемент как ненулевое значение, в то время как другая скомпилированная версия (с одним из неисправных блоков) может случайным образом инициализировать этот элемент как ноль. Я слышал, что это называется «Гейзенбаг», потому что попытка распечатать отладочную информацию может изменить проблему.

Кроме того, убедитесь, что вы проверили, что r равно NULL после Выполнена строка, устанавливающая его значение. Некоторые компиляторы инициализируют указатели в NULL, и это, возможно, еще не было установлено. Также убедитесь, что у вас отключены оптимизации; иногда отладчики плохо работают с оптимизациями, которые могут привести к выполнению строки кода после того, как вы думаете, что она была выполнена.

0 голосов
/ 24 сентября 2010

Ваш конструктор копирования работает так, как он принимает ссылку, и для этого вы передаете ему разыменованный (возможно, нулевой) указатель.Это одна из тех забавных вещей в языке, так как ссылка на разыменованный указатель фактически не разыменовывает указатель, пока вы не используете ссылку (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;
}
0 голосов
/ 24 сентября 2010

Я думаю, что ROILine должен наследоваться от ROI.Сделайте рисование виртуальным в ROILine и затем

ROILine * r = v-> ROI ();r-> рисовать ();// отладка показывает, что r! = 0x0

должно работать ...

Связано с проблемой (или нет) Это плохая практика вызывать функцию, возвращающую ваш ROI точно так же, как конструктор ROI.

(имеется в виду: ROILine * ROI () {return _roi;} // setter выполняет некоторые функции управления ...)

Возможно, компилятор запутался ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...