1

我在不同平台上使用 G++ (4.5.2) 遇到了一个非常奇怪的行为;这是代码:

class Class
{
private:
  std::string rString;

public:
  Class()
  {
    this->rString = "random string";
    std::cout << "Constructor of Class" << std::endl;
  }

  virtual ~Class()
  {
    std::cout << "Destructor of Class" << std::endl;
  }

  void          say() const
  {
    std::cout << "Just saying ..." << std::endl;
    if (this == NULL)
      std::cout << "Man that's really bad" << std::endl;
  }

  void          hello() const
  {
    std::cout << "Hello " << this->rString << std::endl;
  }

};


int     main()
{
  Class *c = NULL;

  /* Dereferencing a NULL pointer results
     in a successful call to the non-static method say()
     without constructing Class */
  (*c).say(); // or c->say()

  /* Dereferencing a NULL pointer and accessing a random
     memory area results in a successful call to say()
     as well */
  c[42000].say();

  /* Dereferencing a NULL pointer and accessing a
     method which needs explicit construction of Class
     results in a Segmentation fault */
  c->hello();

  return (0);
}

问题是,为什么 main 函数中的前两条语句不会使程序崩溃?这是未定义的行为,还是编译器只是调用 Class::say() 就好像它是静态的,因为它没有取消引用方法内的“this”指针?

4

5 回答 5

10

是的,这是未定义的行为。您不能使用空指针调用成员函数

在实践中,前两个确实有效,因为this从未取消引用,因此您的未定义行为不必像第三个那样表现出来,其中内存确实被错误地访问。

(在所有情况下,每次调用它时你都会死在里面,所以不要那样做。)

于 2012-10-18T21:40:11.367 回答
6

未定义的行为只是意味着没有定义发生的事情。这并不意味着“崩溃”。

未定义的行为可以做任何事情,包括按照您想要的方式工作。

于 2012-10-18T21:41:38.237 回答
1

这是未定义的行为。由于您没有将函数用作“虚拟”函数,因此只会静态调用函数。

于 2012-10-18T21:43:31.730 回答
1

这是未定义的行为,尽管它会出现在前两个实例中,它已被优化为在Class::say()不使用对象本身的任何成员变量的情况下调用(因此 this-> 没有被取消引用/使用导致 sigserv),但第三次尝试访问它的成员. 同样,以下可能会在另一个编译器(如 VC++)上出现段错误。

于 2012-10-18T21:43:32.237 回答
0

this在内部,编译器通过简单地将对象指针作为附加参数或与堆栈上的所有适当参数一起传递来实现对非静态、非虚拟函数的调用。

该标准没有规定当使用不是保存相应类或结构的实际对象的内存位置的东西调用成员函数时应该发生什么。要求这样做将需要非 noop 运行时检查(如果可能的话),因此从符合要求的实现中询问是不合理的。

The typing system already makes sure you have go out of your way to call a member function with an object of a wrong type, but checking against NULL or nullptr calls cannot meaningfully be covered by the pointer type.
If you want your binary to crash when a member function is called with the null pointer, making the member function virtual should do the job, because the compiler will have to dereference the vptr of this and the operating system will respond by showing you the finger.

于 2012-10-19T02:13:25.847 回答