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

发布于 2024-11-27 20:38:41 字数 1068 浏览 5 评论 0原文

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

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() 的行超出范围时,程序会导致段错误。我正在使用 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 已经超出了范围。

I'm having a very odd problem that I'm hoping someone has come across.

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

The program causes a seg fault when Board goes out of scope at the line where the virtual function letter->get() is called in the destructor. I'm using gcc 4.1.2. Any ideas?

UPDATE

Okay, it seems what's actually happening in the real code is the equivalent of this:

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

In which case A is already out of scope when the virtual function is called.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

偷得浮生 2024-12-04 20:38:41

我只能猜测您正在尝试将从 get() 返回的 std::string 转换为 char* 。否则我看不出崩溃的原因。

I can only guess you're attempting to cast the std::string returned from get() to a char*. Otherwise i see no reason for the crash.

半边脸i 2024-12-04 20:38:41
#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 没有问题

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

no problem in gcc 4.5.2

以往的大感动 2024-12-04 20:38:41

我没有意识到一个对象正在从堆栈传递给 setLetter(),因此 A 在 b 之前超出了范围。

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

I didn't realize an object was being passed to setLetter() from the stack, so A was going out of scope before b.

Board b;
A a;
b.setLetter(&a);
安穩 2024-12-04 20:38:41

某些编译器不允许普通 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()

另一种解决方案是您安排代码,以便在析构函数之外显式调用您的虚拟方法。

干杯。

Some compilers doesn't allow Plain C / C++ constructors or destructors call virtual methods, seems like the (ANSI) C++ specification neither. And its not recommended.

Sometimes that requirement is useful. Some languages like Object Pascal explicit allow virtual methods calls within constructors and destructors.

One thing you can do its use the "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()

Another solution its that you arrange your code so you explicit call your virtual method outside the destructor.

Cheers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文