调用C ++函数而不进行对象初始化

时间:2011-03-19 06:09:29

标签: c++ pointers object initialization

为什么运行以下代码?

#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不存在时,为什么将值5分配给num,因为还没有创建类型A的对象?

7 个答案:

答案 0 :(得分:4)

代码产生未定义的行为,因为它试图取消引用未初始化的指针。未定义的行为是不可预测的,并且不遵循任何逻辑。出于这个原因,任何关于为什么你的代码做某事或什么不做某事的问题都没有意义。

你问为什么会这样?它没有运行。它会产生未定义的行为

您问的是如何为不存在的成员分配5?它没有任何东西。它会产生未定义的行为

你说输出是5?错误。输出不是5。没有有意义的输出。代码产生未定义的行为。只是因为它在某种程度上碰巧在你的实验中打印5意味着什么都没有,并且没有任何有意义的解释。

答案 1 :(得分:2)

A* a;是一个未初始化的指针。

你看到的价值就是垃圾,幸运的是你不会因为崩溃而结束。

这里没有初始化。

这里没有作业。

你的课程很简单,没有表现出更严重的问题。

A* a(0);会导致崩溃。在某些情况下,未初始化的指针会导致崩溃,并且更容易使用更复杂的类型进行复制。

这是处理未初始化的指针和对象的结果,它指出了编译器警告的重要性。

答案 2 :(得分:2)

您尚未初始化*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?

答案 3 :(得分:1)

A* a;
a->foo();

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

C ++ 03标准中的§4.1/ 1部分说,

  

a的左值(3.10)   非功能,非数组类型T即可   转换为右值。如果T是   不完整的类型,一个程序   需要这种转换是必要的   病态的。如果对象是哪个   左值引用不是类型的对象   T并不是一种类型的对象   派生自T,或如果对象是   未初始化的,一个程序   需要这种转换   未定义的行为。如果T是   非类型,右值的类型   是C的不合格版本的T.   否则,右值的类型是   吨。

请参阅此类似主题:Where exactly does C++ standard say dereferencing an uninitialized pointer is undefined behavior?


  

当num不存在时,为什么它将值5分配给num,因为还没有创建类型A的对象。

这被称为幸运。但它不会发生总是

答案 4 :(得分:1)

这就是我认为的情况。

a->foo(); 因为您只是致电A::foo(a).

而有效

a是一个指针类型变量,位于main的调用堆栈中。 foo()函数在访问位置a时可能会抛出分段错误,但如果没有,则foo()只会从a跳转一些位置并覆盖值为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;
}

答案 5 :(得分:0)

创建对象后,即使您不使用关键字new,也会为该特定对象分配类成员,因为该对象是指向类的指针。因此,您的代码运行正常,并为您提供num的值,但GCC会发出警告,因为您没有明确地实例化该对象。

答案 6 :(得分:0)

我会指出(嘿嘿)你对我之前的一个非常相似的问题的回答:Tiny crashing program

基本上你用指针覆盖了envs堆栈变量,因为你没有在envs声明中添加main

由于envs是一个数组(字符串)数组,它实际上是非常分配的,你用你的5覆盖该列表中的第一个指针,然后再次读取它以打印出来cout

现在这是为什么的答案。你显然不应该依赖