C++没有对象初始化而调用的函数
为什么下面的代码会运行?
#include <iostream>
class A {
int num;
public:
void foo(){ num=5; std::cout<< "num="; std::cout<<num;}
};
int main() {
A* a;
a->foo();
return 0;
}
输出是
num=5
我使用 gcc 对其进行编译,并且在第 10 行仅收到以下编译器警告:(
警告:“a”在此函数中未初始化)
但根据我的理解是,这段代码根本不应该运行吗?当 num 不存在(因为还没有创建 A 类型的对象)时,为什么它会将值 5 赋给 num 呢?
Why does the following code run?
#include <iostream>
class A {
int num;
public:
void foo(){ num=5; std::cout<< "num="; std::cout<<num;}
};
int main() {
A* a;
a->foo();
return 0;
}
The output is
num=5
I compile this using gcc and I get only the following compiler warning at line 10:
(warning: 'a' is used uninitialized in this function)
But as per my understanding, shouldn't this code not run at all? And how come it's assigning the value 5 to num when num doesn't exist because no object of type A has been created yet?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您尚未初始化
*a
。试试这个:
不(正确)初始化指针可能会导致未定义的行为。如果幸运的话,您的指针会指向堆中可供初始化的位置*。 (假设执行此操作时没有引发异常。)如果不幸的话,您将覆盖用于其他目的的一部分内存。如果你真的很不幸,这将被忽视。
这不是安全代码; “黑客”可能会利用它。
*当然,即使您访问该位置,也不能保证它以后不会被“初始化”。
“幸运”(实际上,“幸运”使调试程序变得更加困难):
“不幸”(使调试程序更容易,所以我真的不认为它“不幸”):
You haven't initialized
*a
.Try this:
Not initializing pointers (properly) can lead to undefined behavior. If you're lucky, your pointer points to a location in the heap which is up for initialization*. (Assuming no exception is thrown when you do this.) If you're unlucky, you'll overwrite a portion of the memory being used for other purposes. If you're really unlucky, this will go unnoticed.
This is not safe code; a "hacker" could probably exploit it.
*Of course, even when you access that location, there's no guarantee it won't be "initialized" later.
"Lucky" (actually, being "lucky" makes it more difficult to debug your program):
"Unlucky" (makes it easier to debug your program, so I don't consider it "unlucky", really):
A* a;
是一个未初始化的指针。你看到的值是垃圾,幸运的是你没有崩溃。
这里没有初始化。
这里没有任务。
你的课程恰好足够简单,没有表现出更严重的问题。
A* a(0);
会导致崩溃。未初始化的指针在某些情况下会导致崩溃,并且更容易使用更复杂的类型来重现。这是处理未初始化的指针和对象的结果,它指出了编译器警告的重要性。
A* a;
is an uninitialized pointer.the value you see is garbage, and you are luck you did not end up with a crash.
there is no initialization here.
there is no assignment here.
your class happens to be simple enough that more serious issues are not exhibited.
A* a(0);
would lead to a crash. an uninitialized pointer would lead to a crash in some cases, and is more easily reproduced with more complex types.this is the consequence of dealing with uninitialized pointers and objects, and it points out the importance of compiler warnings.
这会调用未定义的行为。最常见的是它使程序崩溃。
C++03 标准的第 §4.1/1 节说:
请参阅此类似主题:其中C++ 标准到底说取消引用未初始化的指针是未定义的行为吗?
这就是所谓的幸运。但这不会总是发生。
That invokes undefined behaviour. Most commonly it crashes the program.
The section §4.1/1 from the C++03 Standard says,
See this similar topic: Where exactly does C++ standard say dereferencing an uninitialized pointer is undefined behavior?
It's called being lucky. But it wouldn't happen always.
我认为这就是发生的情况。
a->foo();
之所以有效,是因为您只是调用
A::foo(a)。
a
是一个位于 main 调用堆栈中的指针类型变量。当访问位置a
时,foo()
函数可能会抛出分段错误,但如果没有,则foo()
只会跳转一些位置并用值 5 覆盖 4 个字节的内存。然后读出相同的值。我是对还是错?请告诉我,我正在学习调用堆栈,如果您对我的答案有任何反馈,我将不胜感激。
另请看下面的代码
This is what I think happens.
a->foo();
works because you are just calling
A::foo(a).
a
is a pointer type variable that is in main's call stack.foo()
function may throw a segmentation error when locationa
is accessed, but if it does not, thenfoo()
just jumps some locations from a and overwrites 4 bytes of memory with the value 5. It then reads out the same value.Am I right or wrong? Please let me know, I am learning about call stacks and would appreciate any feedback on my answer.
Also look at the following code
创建对象时,即使不使用关键字 new,也会为该特定对象分配类成员,因为该对象是指向类的指针。因此,您的代码运行良好,并为您提供了
num
的值,但 GCC 会发出警告,因为您尚未显式实例化该对象。Upon object creation, the class members are allocated for that particular object even if you don't use the keyword
new
, since the object is pointer to class. So your code runs fine and gives you the value ofnum
, but GCC issues a warning because you've not instantiated the object explicitly.我会向您指出(呵呵)我之前对一个非常相似的问题的回答:微小崩溃 基本上,您
正在用指针覆盖
envs
堆栈变量,因为您尚未将envs
添加到main
声明中。由于
envs
是一个数组(字符串)数组,因此它实际上分配了很多空间,并且您将使用5
覆盖该列表中的第一个指针,然后再次读取它使用cout
打印。现在,这是为什么会发生这种情况的答案。显然您不应该依赖这一点。
I'll point (hehe) you to a previous answer of mine to a very similar question: Tiny crashing program
Basically you're overwriting the
envs
stack variable with your pointer because you haven't addedenvs
to themain
declaration.Since
envs
is an array of arrays (strings), it's actually very much allocated, and you're overwriting the first pointer in that list with your5
, then reading it again to print withcout
.Now this is an answer to why it happens. You should obviously not rely on this.
该代码会产生未定义的行为,因为它尝试取消引用未初始化的指针。未定义的行为是不可预测的,并且不遵循任何逻辑。因此,任何关于代码为什么执行某些操作或不执行某些操作的问题都是没有意义的。
你问它为什么运行?它不运行。它会产生未定义的行为。
您问如何将 5 分配给不存在的成员?它不会将任何东西分配给任何东西。它会产生未定义的行为。
你是说输出是
5
?错误的。输出不是5
。没有任何有意义的输出。该代码会产生未定义的行为。仅仅因为在你的实验中以某种方式碰巧打印了5
就绝对没有任何意义,也没有任何有意义的解释。The code produces undefined behavior, because it attempts to dereference an uninitialized pointer. Undefined behavior is unpredictable and follows no logic whatsoever. For this reason, any questions about why your code does something or doesn't do something make no sense.
You are asking why it runs? It doesn't run. It produces undefined behavior.
You are asking how it is assigning 5 to a non-existing member? It doesn't assign anything to anything. It produces undefined behavior.
You are saying the output is
5
? Wrong. The output is not5
. There's no meaningful output. The code produces undefined behavior. Just because it somehow happened to print5
in your experiment means absolutely nothing and has no meaningful explanation.