3

例如在这两个代码中,一个不需要指针,另一个不需要指针。为什么是这样?如果 myObject1 不是指针,那么它到底是什么?

class Object{
…
};


int main(){
    // Create instance on the stack
    Object myObject1;

    // Create instance on the heap
    Object *myObject2 = new Object;

    return 0;
}

谢谢你的帮助。

4

7 回答 7

7

您的两个声明都是具有自动存储持续时间的对象的定义。也就是说,它们都将在函数结束时被销毁。第一个是声明一个Object类型对象,第二个是一个Object*类型对象。

碰巧 for 的初始化程序myObject2是一个new-expression。一个新的表达式动态分配一个对象并返回一个指向它的指针。myObject2正在使用指向动态分配的指针进行初始化Object

因此,您正在目睹两种不同的创建对象的方式。一种是带有变量定义的,一种是带有new-expression 的

任何其他方式都没有任何意义。想象一下,一个new 表达式没有返回指向对象的指针,而是直接引用了该对象。然后你可能会写这样的东西:

Object myObject2 = new Object();

但是,C++ 默认使用值语义。这意味着动态分配的对象将被复制到myObject2其中,然后您就忘记了它。你没有办法再得到那个对象的地址了。新表达式返回一个指针,以便您拥有动态分配对象的句柄。

您可能会说,“这就是我用 Java 编写它的方式!” 但那是因为 Java 以不同的方式工作。在 Java 中,myObject2是您设置为指向新Object对象的引用。它不会以任何方式复制对象。

C++ 不要求在动态分配对象时必须使用指针。事实上,你可以做这样的事情(这是一种 Java 等价物):

Object& myObject2 = *(new Object());

但这是一个非常糟糕的主意。它突然掩盖了对象是动态分配的事实,并且很容易出错并忘记销毁对象(在Java中您不必关心)。至少有一个指针可能会提醒您这样做。然而,即使这样也可能导致错误或不清楚的代码,这就是为什么建议您尽可能使用智能指针。

简而言之:这就是new-expression 的行为方式。它动态分配一个对象,然后返回一个指向它的指针。

于 2013-04-18T11:07:55.930 回答
4

它是一个类的实例(或对象)。myObject2 指向一个类的实例。

您也可以将指针指向堆栈上的变量:

int main()
{
    Object myObject1;
    Object* pointerToObjectOnStack = &myObject1;
}

指针可以指向任何地方;堆栈,堆或全局变量(既不在堆栈上,也不在堆上)。

于 2013-04-18T11:06:17.720 回答
1

例如在这两个代码中,一个不需要指针,另一个不需要指针。为什么是这样?

因为您以这种方式编写它们是为了(未保证)尝试与您在上面写的评论相匹配。

如果 myObject1 不是指针,那么它到底是什么?

一个Object。即,类型为 的对象Object。也就是Object类的一个实例。

于 2013-04-18T11:05:30.723 回答
1

myObject1Object在堆栈中分配的。

在这里,您将找到有关内存的更准确信息。

用两句话来说:

  1. 函数上的所有局部变量(包括对象实例)都分配在stack中。
  2. 所有动态分配(使用newor malloc())的数据都在堆中分配。
于 2013-04-18T11:06:21.740 回答
1

当您在堆栈上分配对象时,编译器会为您完成所有脏活(分配/解除分配),因此实际上您不需要指针来使用该对象。当您引用 myObject1 时,您指的是它Object本身,您可以简单地访问它的字段、方法等。

请注意,您始终可以使用&运算符获取指向堆栈上变量的指针。

Object myObject1; // This is the live instance of Object
Object * pObject1 = &myObject1; // Here you can obtain a pointer
                                // to myObject1
myObject1.someField = 42;       // Accessing myObject1's data

另一方面,在堆上分配对象需要您管理这些对象(使用 new/delete、malloc/free 等手动分配/取消分配它们),因此首先您获得指向内存的指针,对象所在的位置和使用它,您必须使用*运算符取消引用它。

Object * myObject1 = new Object(); // Here you construct the Object manually
                                   // and get the pointer to place, where Object
                                   // was allocated.
(*myObject1).someField = 42;       // Accessing myObject1's data, notice the 
                                   // dereference (*)
myObject1->someField = 42;         // The same, written more easily
于 2013-04-18T11:08:00.653 回答
0

当函数与一些元数据一起被调用时,作为函数一部分的每个对象都会在堆栈上分配。此元数据结构是在编译器编译函数时定义的 -> 这会导致从函数快速访问这些变量(相对位置不会改变)。当函数返回时,这个内存也总是(自动)空闲的。

虽然堆设置在内存的不同部分并且可以或不能根据逻辑使用。

你有一个错误,通过将代码分成两行很容易显示:

class Object{
…
};

int main(){
    // Create instance of Object on the stack
    Object myObject1;

    // Create instance of a pointer to Object on the stack
    Object *myObject2;

    // Create instance of Object on the Heap and assigned its address to the pointer.
    myObject2 = new Object;

    return 0;
}
于 2013-04-18T11:20:35.847 回答
-3

如果变量是在堆栈上分配的,编译器会为您隐式生成一个指针。

ieObject myObject1; myObject1.foo(); 将被编译为

Object* myObject1_implicit_ptr = new(alloca(sizeof(Object))) Object;
myObject1_implicit_ptr->foo();

alloca在堆栈上分配内存)


In是对象实例所在的内存位置的名称,即其地址的别名(相对于堆栈帧指针)Object myObject1;。 我们可以查询该地址并将其存储到一个指针(一个保存地址的变量)中: myObject1
operator&

Object myObject1; // myObject1 == stack-frame-pointer + 123
Object* myObject1_ptr = &myObject1;
于 2013-04-18T11:11:14.820 回答