C++没有对象初始化而调用的函数

发布于 2024-10-24 06:01:19 字数 461 浏览 1 评论 0原文

为什么下面的代码会运行?

#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 技术交流群。

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

发布评论

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

评论(7

我不咬妳我踢妳 2024-10-31 06:01:20

您尚未初始化*a

试试这个:

#include <iostream>

class A
{
    int num;
    public:
        void foo(){ std::cout<< "num="; num=5; std::cout<<num;}
};

int main()
{
    A* a = new A();
    a->foo();
    return 0;
}

不(正确)初始化指针可能会导致未定义的行为。如果幸运的话,您的指针会指向堆中可供初始化的位置*。 (假设执行此操作时没有引发异常。)如果不幸的话,您将覆盖用于其他目的的一部分内存。如果你真的很不幸,这将被忽视。

这不是安全代码; “黑客”可能会利用它。

*当然,即使您访问该位置,也不能保证它以后不会被“初始化”。


“幸运”(实际上,“幸运”使调试程序变得更加困难):

// uninitialized memory 0x00000042 to 0x0000004B
A* a;
// a = 0x00000042;
*a = "lalalalala";
// "Nothing" happens

“不幸”(使调试程序更容易,所以我真的不认为它“不幸”):

void* a;
// a = &main;
*a = "lalalalala";
// Not good. *Might* cause a crash.
// Perhaps someone can tell me exactly what'll happen?

You haven't initialized *a.

Try this:

#include <iostream>

class A
{
    int num;
    public:
        void foo(){ std::cout<< "num="; num=5; std::cout<<num;}
};

int main()
{
    A* a = new A();
    a->foo();
    return 0;
}

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

// uninitialized memory 0x00000042 to 0x0000004B
A* a;
// a = 0x00000042;
*a = "lalalalala";
// "Nothing" happens

"Unlucky" (makes it easier to debug your program, so I don't consider it "unlucky", really):

void* a;
// a = &main;
*a = "lalalalala";
// Not good. *Might* cause a crash.
// Perhaps someone can tell me exactly what'll happen?
朕就是辣么酷 2024-10-31 06:01:20

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.

征﹌骨岁月お 2024-10-31 06:01:20
A* a;
a->foo();

这会调用未定义的行为。最常见的是它使程序崩溃。

C++03 标准的第 §4.1/1 节说:

a 的左值 (3.10)
非函数、非数组类型 T 可以是
转换为右值。如果 T 是一个
不完全类型,一个程序
需要进行此转换的是
格式不正确。如果对象
左值引用的不是类型的对象
T 并且不是类型的对象
从 T 派生,或者如果对象是
未初始化的程序
需要这种转换
未定义的行为
。如果 T 是一个
非类类型,右值的类型
是 T 的 cv-unqualified 版本。
否则,右值的类型为

请参阅此类似主题:​​其中C++ 标准到底说取消引用未初始化的指针是未定义的行为吗?


当 num 不存在时,为什么会为 num 赋值 5,因为尚未创建 A 类型的对象。

这就是所谓的幸运。但这不会总是发生。

A* a;
a->foo();

That invokes undefined behaviour. Most commonly it crashes the program.

The section §4.1/1 from the C++03 Standard says,

An lvalue (3.10) of a
non-function, non-array type T can be
converted to an rvalue. If T is an
incomplete type, a program that
necessitates this conversion is
ill-formed. If the object to which the
lvalue refers is not an object of type
T and is not an object of a type
derived from T, or if the object is
uninitialized, a program that
necessitates this conversion has
undefined behavior
. If T is a
non-class type, the type of the rvalue
is the cv-unqualified version of T.
Otherwise, the type of the rvalue is
T.

See this similar topic: Where exactly does C++ standard say dereferencing an uninitialized pointer is undefined behavior?


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.

It's called being lucky. But it wouldn't happen always.

山川志 2024-10-31 06:01:20

我认为这就是发生的情况。

a->foo();
之所以有效,是因为您只是调用 A::foo(a)。

a 是一个位于 main 调用堆栈中的指针类型变量。当访问位置a时,foo()函数可能会抛出分段错误,但如果没有,则foo()只会跳转一些位置并用值 5 覆盖 4 个字节的内存。然后读出相同的值。

我是对还是错?请告诉我,我正在学习调用堆栈,如果您对我的答案有任何反馈,我将不胜感激。

另请看下面的代码

#include<iostream>
class A {
    int num;
    public:
        void foo(){ num=5; std::cout<< "num="; std::cout<<num;}
};

int main() {

    A* a;
    std::cout<<"sizeof A is "<<sizeof(A*)<<std::endl;
    std::cout<<"sizeof int is "<<sizeof(int)<<std::endl;
    int buffer=44;
    std::cout<<"buffer is "<<buffer<<std::endl;
    a=(A*)&buffer;

    a->foo();
    std::cout<<"\nbuffer is "<<buffer<<std::endl;
    return 0;
}

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 location a is accessed, but if it does not, then foo() 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

#include<iostream>
class A {
    int num;
    public:
        void foo(){ num=5; std::cout<< "num="; std::cout<<num;}
};

int main() {

    A* a;
    std::cout<<"sizeof A is "<<sizeof(A*)<<std::endl;
    std::cout<<"sizeof int is "<<sizeof(int)<<std::endl;
    int buffer=44;
    std::cout<<"buffer is "<<buffer<<std::endl;
    a=(A*)&buffer;

    a->foo();
    std::cout<<"\nbuffer is "<<buffer<<std::endl;
    return 0;
}
落墨 2024-10-31 06:01:20

创建对象时,即使不使用关键字 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 of num, but GCC issues a warning because you've not instantiated the object explicitly.

当爱已成负担 2024-10-31 06:01:20

我会向您指出(呵呵)我之前对一个非常相似的问题的回答:微小崩溃 基本上,您

正在用指针覆盖 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 added envs to the main 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 your 5, then reading it again to print with cout.

Now this is an answer to why it happens. You should obviously not rely on this.

帅的被狗咬 2024-10-31 06:01:19

该代码会产生未定义的行为,因为它尝试取消引用未初始化的指针。未定义的行为是不可预测的,并且不遵循任何逻辑。因此,任何关于代码为什么执行某些操作或不执行某些操作的问题都是没有意义的。

你问它为什么运行?它不运行。它会产生未定义的行为

您问如何将 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 not 5. There's no meaningful output. The code produces undefined behavior. Just because it somehow happened to print 5 in your experiment means absolutely nothing and has no meaningful explanation.

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