在析构函数中调用成员变量的虚函数会导致 seg 错误

Calling member variable's virtual function within destructor causes seg fault

本文关键字:函数 错误 seg 析构函数 调用 成员 变量      更新时间:2023-10-16

我遇到了一个非常奇怪的问题,我希望有人能发现。

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在析构函数中调用虚函数letter->get()的那一行超出作用域时,程序导致segfault。我使用的是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已经超出了作用域

我只能猜测您试图将get()返回的std::字符串转换为char*。否则我看不出崩溃的原因。

#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;
}

我没有意识到一个对象正在从堆栈传递给setLetter(),所以A在b之前超出了作用域。

Board b;
A a;
b.setLetter(&a);

一些编译器不允许普通C/c++构造函数或析构函数调用虚方法,这似乎也不符合(ANSI) c++规范。这是不推荐的。

有时候这个要求是有用的。有些语言,如Object Pascal,明确允许在构造函数和析构函数中调用虚方法。

你可以使用"Fake Virtual Constructor Pattern":

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()

另一个解决方案是你安排你的代码,使你显式调用你的虚方法外的析构函数。

欢呼。