操作员新手做什么?

时间:2014-12-31 14:47:46

标签: c++

我试图找出new的工作原理:

#include <iostream>
using namespace std;

struct munch{
    int x;
};

int main(){
    munch *a;
    //1
    cout << a << endl;
    cout << a->x << endl;
    //1
    cout << endl;
    //2
    a= new munch;
    cout << a << endl;
    cout << a->x << endl;
    //2
    cout << endl;
    //3
    a= new munch;
    cout << a << endl;
    cout << a->x << endl;
    //3
}

1,2和3之间的区别是什么?为什么operator new给指向struct一个新位置的指针,但是没有改变a->x的值?但在调用new的第一个实例之前,它的值与调用new之后的值不同吗?

7 个答案:

答案 0 :(得分:2)

[1]是未定义的行为,因为它试图取消引用未初始化的指针。

[2]和[3]是相同的,可能导致未定义的行为,尽管至少你会在struct中获得字段的垃圾值。

更多关于标准所说的[2]和[3]: -

C 1999标准在6.7.8 10中说,“如果没有明确初始化具有自动存储持续时间的对象,则其值是不确定的。”

此外,如果左值指定了一个自动存储持续时间的对象,该对象可能已使用寄存器存储类声明(从未使用过其地址),并且该对象未初始化(未使用初始化程序声明且未分配如果在使用之前已经执行过,那么行为是未定义的。

答案 1 :(得分:2)

在第一种情况下,您正在读取未初始化的指针,undefined behaviouraa->x未定义)。

另外两个例子中重要的是munchPlain Old Data。这意味着new munch does not initialize新分配的结构的字段。因此,阅读a->x也会导致未定义的行为。

这是C ++,您可以向munch添加一个构造函数,该构造函数将初始化x并使示例2和3定义明确。

答案 2 :(得分:2)

1中,您已声明指向munch的指针,但尚未对其进行初始化。因此,cout << a << endl;cout << a->x << endl;都是未定义的行为,因为它们尚未初始化。在23中(在代码方面无法找到两者之间的差异),第一行cout << a << endl;现在已定义为行为,因为您已为内存地址分配a来自a = new munch;。但是,a->x仍然未初始化(您从未使用a->x = 5;之类的内容进行设置),因此在这两种情况下,cout << a->x << endl;仍然是未定义的行为。

答案 3 :(得分:1)

首先,让我们澄清你的语义。

请注意语言中有 new-expression operator new

定义了various forms of operator new,如展示位置1,不可抛弃的全局版本和可替换的全局版本。

new-expression 包括调用其中一个分配函数,然后执行任何初始化。
如果第二部分失败,它也将调用相应的去初始化函数。

所以,让我们来看看你有什么:

在第一种情况下,只读取未初始化的非静态(因此不确定)指针为Undefined Behavior

在第2和第3例中,由于munch是POD类型,因此 new-expression 不会导致构造函数调用,这意味着所有成员都保持未初始化状态,从而读取{ {1}}是UB。

答案 4 :(得分:0)

因为x的值是垃圾值,因为您没有在任何地方初始化它。并且a的第一个值也是垃圾,你也没有在任何地方指出它。

new运算符从操作系统请求一个内存段并调用类构造函数,返回指向该内存的指针并将其地址存储在变量中。

由于munch没有构造函数,因此它永远不会初始化x

所有代码都有未定义的行为,所以你永远不应该这样做,使用动态内存分配的munch结构的正确方法是

munch *a;

a = new munch;
a->x = SOME_INITIAL_VALUE;

std::cout << "address of a : " << a << std::endl;
std::cout << "value of a->x: " << a->x << std::endl;

或者在结构中添加构造函数,您可以在其中初始化x

struct munch 
{
    public:
        munch(int initial_x = SOME_INITIAL_VALUE) : x(initial_x) {}
        int x;
};

munch *a;

a = new munch;

std::cout << "address of a : " << a << std::endl;
std::cout << "value of a->x: " << a->x << std::endl;

答案 5 :(得分:0)

当你声明一个变量struct munch时,编译器会做什么,它只需要大小相当于sizeof(munch)的内存块,并为它指定一个你给出的名称。

但是在指针声明的情况下,编译器只是为内存位置指定一个名称,并且在您明确指定它之前不会分配任何内存(使用new运算符)。

例如:

munch *a;

此语句只是将名称a指定给内存位置。 因此,cout<<a将打印该内存地址。

当你执行cout<<a->x时,它会给你运行时错误,因为你没有分配空间。所以你现在没有任何价值。

// 2

首先,将给出a指向的新内存位置。由于new运算符,将分配内存。 struct中的变量将具有已分配的内存位置的默认值。

因此,当您执行cout<<a时,它会打印a的新位置。 当你cout<<a->x时,它会给出一些随机值。如果你编译&amp;一次又一次地运行程序,每次都可能得到不同的值。

// 3

与案例#2一样,同样的事情也会发生。首先,将选择新的内存位置,a将指向该位置。然后将打印结果,但由于内存位置不同,值可能与情况#2不同。

答案 6 :(得分:0)

new运算符为堆上的实例分配内存并返回指针。对于您的代码,1。在堆栈上分配一个项目。 2和3在堆上分配项目。当我运行你提供的代码时,我在所有3个实例中获得了不同的x值(CodeLite / MingGW):

  

0x417d7e

     

1528349827

     

0x8f6bd8

     

12

     

0x8f6be8

     

14

每个新的都应该伴随删除。