Вызов виртуальной функции переменной-члена в деструкторе вызывает ошибку seg - PullRequest
0 голосов
/ 03 августа 2011

У меня очень странная проблема, с которой я надеюсь, что кто-то сталкивался.

class Letter
{
public:
    Letter()
    virtual ~Letter()
    virtual std::string get() const = 0;
};

class A : public Letter
{
public:
    A()
    ~A()
    virtual std::string get() const { return "A"; }
};

class Board
{
public:
   Board(){}
   ~Board()
   {
        std::cout << "Removing: " << letter->get() << std::endl;
        delete letter;
   }
   void setLetter(Letter * l) { letter = l }
private:
   Letter * letter;
}

int main()
{
    Board b;
    b.setLetter(new A());
}

Программа вызывает ошибку сегмента, когда Board выходит из области видимости в строке, где буква виртуальной функции-> get () вызывается в деструкторе.Я использую gcc 4.1.2.Есть идеи?

ОБНОВЛЕНИЕ

Хорошо, кажется, что то, что на самом деле происходит в реальном коде, эквивалентно этому:

class Board
{
public:
   Board(){}
   ~Board()
   {
       std::cout << "Removing: " << letter->get() << std::endl;
   }
   void setLetter(Letter * l) { letter = l; }
private:
   Letter* letter;
};

int main()
{
    Board b;
    A a;
    b.setLetter(&a);

    return 0;
}

В которомслучай A уже выходит за рамки при вызове виртуальной функции.

Ответы [ 4 ]

1 голос
/ 03 августа 2011

Я могу только догадываться, что вы пытаетесь привести std :: string, возвращенную из get (), к char *.В противном случае я не вижу причин для аварии.

0 голосов
/ 18 сентября 2012

Я не осознавал, что объект передавался в setLetter () из стека, поэтому A выходил из области видимости до b.

Board b;
A a;
b.setLetter(&a);
0 голосов
/ 03 августа 2011
#include <iostream>
#include <string>
using namespace std;

class Letter
{
public:
    Letter() {}
    virtual ~Letter() {}
    virtual std::string get() const = 0;
};

class A : public Letter
{
public:
    A() {}
    ~A() {}
    virtual std::string get() const { return "A"; }
};

class Board
{
public:
   Board(){}
   ~Board()
   {
        std::cout << "Removing: " << letter->get() << std::endl;
        delete letter;
   }
   void setLetter(Letter * l) { letter = l; }
private:
   Letter * letter;
};

int main()
{
    Board b;
    b.setLetter(new A());
    return 0;
}

без проблем в gcc 4.5.2

0 голосов
/ 03 августа 2011

Некоторые компиляторы не допускают, чтобы конструкторы или деструкторы Plain C / C ++ вызывали виртуальные методы, похоже на спецификацию (ANSI) C ++. И это не рекомендуется.

Иногда это требование полезно. Некоторые языки, такие как явный Object Pascal, допускают вызовы виртуальных методов внутри конструкторов и деструкторов.

Одна вещь, которую вы можете сделать, это использовать «Поддельный шаблон виртуального конструктора»:

class MyClass
{
  public:
    // constructor
    MyClass
    {
      // anything but virtual methods
    }

    // destructor
    ~MyClass
    {
      // anything but virtual methods
    }

    virtual void MyFakeConstructor()
    {
      MyVirtualMethod();
    }

    virtual void MyFakeDestructor()
    {
      MyVirtualMethod();
    }

    virtual void MyVirtualMethod()
    {
      // more stuff
    }

    // more members
}

int main(char[][] Args)
{
  MyClass MyObject = new MyClass();
  MyObject->MyFakeConstructor(); // <-- calls "MyVirtualMethod()"

  MyObject->DoSomething1();
  MyObject->DoSomething2();
  MyObject->DoSomething3();

  MyObject->MyFakeDestructor(); // <-- calls "MyVirtualMethod()"
  delete MyObject;

  return 0;
} // int main()

Другое решение заключается в том, что вы упорядочиваете свой код так, чтобы явно вызывать виртуальный метод вне деструктора.

Приветствие.

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