C++ 为什么这会发生在C++;?
我在不同的平台上使用G++(4.5.2)时遇到了一个非常奇怪的行为;代码如下:C++ 为什么这会发生在C++;?,c++,g++,undefined-behavior,C++,G++,Undefined Behavior,我在不同的平台上使用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
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);
}
类
{
私人:
std::字符串rString;
公众:
类()
{
此->rString=“随机字符串”;
是的,这是未定义的行为
在实践中,前两种方法确实有效,因为此
从未被取消引用,因此您未定义的行为不必像第三种方法那样表现出来,因为第三种方法确实错误地访问了内存
(在所有情况下,每次它被调用时,你都会在里面死一点,所以不要这样做。)是的,这是未定义的行为
在实践中,前两种方法确实有效,因为此
从未被取消引用,因此您未定义的行为不必像第三种方法那样表现出来,因为第三种方法确实错误地访问了内存
(在所有情况下,每次调用它时,你都会在里面死一点,所以不要这样做。)未定义的行为只是意味着发生的事情没有定义。它并不意味着“崩溃”
未定义的行为可以做任何事情,包括按您希望的方式工作。未定义的行为只意味着发生的事情没有定义。它并不意味着“崩溃”
未定义的行为可以做任何事情,包括按您希望的方式工作。这是未定义的行为。因为您没有将函数用作“虚拟”函数,所以只会静态调用函数。这是未定义的行为。因为您没有将函数用作“虚拟”函数这将只是静态地调用函数。这是未定义的行为,尽管它会出现在前两个实例中,它已优化为调用类::say()
,而不使用对象本身的任何成员变量(因此->未被取消引用/使用导致sigserv),但第三个尝试访问它的成员。同样,下面的代码可能会在另一个编译器(如VC++)上出现故障。这是未定义的行为,尽管它会出现在前两个实例中,它已优化为调用类::say()
,而不使用对象本身的任何成员变量(因此该->未被取消引用/使用,导致sigserv),但第三个尝试访问它的成员。同样,下面的代码可能会在另一个编译器(如VC++)上出现故障。在内部,编译器只需将对象指针this
作为附加参数传递,或者与堆栈上的所有正确参数一起传递,即可实现对非静态、非虚拟函数的调用。
该标准没有规定当使用非内存位置的对象调用成员函数时应该发生什么。如果需要,则需要进行非noop运行时检查(如果可能的话),因此从一致性实现中询问是不合理的
键入系统已经确保您用错误类型的对象调用成员函数,但指针类型无法有效地覆盖对NULL
或NULL ptr
调用的检查。
如果您希望在使用null指针调用成员函数时二进制文件崩溃,则应使成员函数虚拟化,因为编译器必须取消对this
的vptr的引用,操作系统将通过向您显示指针来响应。在内部,编译器实现对n的调用在静态非虚函数上,只需将对象指针this
作为附加参数传递,或者与堆栈上的所有正确参数一起传递
该标准没有规定当使用非内存位置的对象调用成员函数时应该发生什么。如果需要,则需要进行非noop运行时检查(如果可能的话),因此从一致性实现中询问是不合理的
键入系统已经确保您用错误类型的对象调用成员函数,但指针类型无法有效地覆盖对NULL
或NULL ptr
调用的检查。
如果您希望在使用空指针调用成员函数时二进制文件崩溃,则应使成员函数虚拟化,因为编译器必须取消对this
的vptr的引用,操作系统将通过显示手指来响应。从技术上讲,使用this
(在类::say
)内部),但它从未被解除引用。因此没有无效的内存访问。@bitmask:是的,我说得太松散了。:)这就是我们Nit Pickers Inc.的目的。从技术上讲,这个
(在类::say
内部),但它永远不会被取消引用。因此不会有无效的内存访问。@位掩码:是的,我说得太松散了。:)这就是我们在Nit Pickers Inc.的目的。您的编辑完全没有必要,而且被误导了:inline
在这里没有效果,因为类中定义的函数会自动inline
。您错了,编译器可能会也可能不会inline
这些方法在他将生成的二进制文件中。J因为这些方法是在类class
中定义和实现的,所以它们并不自动意味着它们实际上是内联的。另外,在原型前面加上inline
关键字也不意味着编译器将内联这些代码。我只是给编译器一个提示,说生成一个prol每种方法的og都可能很重。不,你错了。你收集了一些基本正确但不完全正确的信息。(§7.1.2/3标准)。请注意,inline
的效果不仅仅是建议编译器执行调用内联。§7.1.2有更多的作用