在c++中,对象和对象指针之间的区别是什么?

时间:2022-06-02 13:19:47

In java and objective-c, a variable representing an object is generally a pointer to that object. However, it seems that in C++, it's common to have non-pointer types hold objects. What's the difference between the two?

在java和objective-c中,表示对象的变量通常是指向该对象的指针。然而,在c++中,非指针类型持有对象似乎很常见。这两者有什么区别?

If I pass a struct as an argument to a function, I believe I'm passing by value, meaning I'm actually creating a new struct in memory, and changes to that struct inside the function its passed to won't affect the "source" struct outside the function. However, if I pass a pointer to a struct, there's still only one original struct, and changes to the struct referenced by the pointer will be visible to any code which is aware of this struct. Do I have that right?

如果我传递一个struct作为一个函数的参数,我相信我正在传递一个值,这意味着我实际上在内存中创建了一个新的struct,并且在函数内部对这个struct进行了更改,从而不会影响函数之外的“源”结构。但是,如果我传递一个指向一个struct的指针,仍然只有一个原始的struct,指针引用的struct的更改对任何知道这个struct的代码都是可见的。我说对了吗?

So, is there any difference with objects? When I pass a non-pointer object to a function, does the entire object get copied?

那么,这和物体有什么区别吗?当我将一个非指针对象传递给一个函数时,整个对象会被复制吗?

6 个解决方案

#1


15  

It's exactly as you said.

正如你所说的。

When you pass an object by value, its copy constructor is invoked to produce a new instance of such object that will be used inside the function. The changes done to such new object won't be reflected to the original one1.

当您按值传递一个对象时,将调用其复制构造函数来生成该对象的新实例,该实例将用于函数内。对这种新对象所做的更改不会反映到原始对象1。

As with structures, the default copy constructor just does a shallow copy of the original object - i.e., its fields are copied2 to the new instance; in many cases this is not desirable (e.g. if the object wraps a pointer/another resource), so there are classes which redefine the copy constructor or disable it completely. Objects of these last classes can only be passed by pointer or reference.

与结构一样,默认的复制构造函数只对原始对象做一个浅拷贝——即。,其字段复制到新实例;在许多情况下,这是不可取的(例如,如果对象包装一个指针/另一个资源),所以有一些类重新定义复制构造函数或完全禁用它。这些最后类的对象只能通过指针或引用传递。

Passing objects by value can be costly if they are bigger than a pointer (in size) or in general if their copy constructor isn't "cheap". On the other hand, in comparison to pointers, the pass-by-value yields the usual advantages of not having to specify the pointer ownership, letting the callee do whatever it wants with the object, etc.

如果对象的值大于指针(大小),或者一般情况下,如果它们的复制构造函数不“便宜”,那么通过值传递对象的代价可能很高。另一方面,与指针相比,按值传递产生了通常的优点,即不必指定指针所有权,让被调用者对对象做任何想做的事情,等等。

Notice that passing an object by value kills the polymorphism. This because a function receiving an object by value receives a statically typed object, with a precise size and type, so any attempt to pass an object of a derived class will result in object slicing (the copy constructor for the base class is called, that by default just copies the fields that are available in the base class).

注意,按值传递对象会杀死多态性。这是因为一个函数接收一个对象的值接收一个静态类型的对象,具有精确的尺寸和类型,所以任何试图通过一个派生类的对象将导致对象切片(调用基类的拷贝构造函数,默认情况下只复制基类中的字段可用)。

This is the reason why often the preferred method of passing objects is by const reference. This yields several advantages:

这就是为什么通常首选的传递对象的方法是使用const引用的原因。这个收益率几个优势:

  • no copies involved; the object that the callee will see will be exactly the one specified at the moment of the call;
  • 涉及任何副本;被调用者将看到的对象将与调用时指定的对象完全相同;
  • no changes to the original object can be made, thanks to the const qualifier;
  • 由于const限定符,无法对原始对象进行更改;
  • if however the callee needs to change a copy of the object, it can still construct a copy by itself from the reference;
  • 但是,如果callee需要更改该对象的副本,它仍然可以从引用本身构造一个副本;
  • no awkward pointer syntax;
  • 没有尴尬的指针语法;
  • polymorphism preserved, since behind the scenes we're actually passing a pointer;
  • 多态性保留了下来,因为在幕后我们实际上传递一个指针;
  • no big doubts about object ownership: the general rule about references is that they are owned by the caller.
  • 关于对象所有权没有什么大的疑问:关于引用的一般规则是引用属于调用者。

  1. As far as the "raw fields" of the object are concerned; naturally if the original object and the copy continue to share a pointer/handle to the same resource some modifications to one may affect the other.

    关于对象的“原始字段”;自然,如果原始对象和副本继续共享同一资源的指针/句柄,某些修改可能会影响到另一个。

  2. Primitive types (and in general PODs) are copied bitwise, while the copy constructor is called for non-POD types.

    原始类型(在一般的pod中)按位复制,而复制构造函数用于非pod类型。

#2


3  

The difference mostly has to do with where in memory an object is allocated. For instance:

差异主要与在内存中分配对象的位置有关。例如:

int main() {
    MyObject x;   //allocates space for an instance of MyObject on the stack
    MyObject* y;  //allocates space for a pointer on the stack
    MyObject* z = new MyObject();  //allocates space for a pointer on the 
                                   //stack and an object instance in the heap and
                                   //sets the pointer to point to the new instance
    MyObject* a = &x;  //allocates space for a pointer on the stack and 
                       //makes it point to 'x'
    ...
}

int someFunc(MyObject byValue, MyObject* byReference) {
   //the 'byValue' parameter will be passed by creating a copy of the 
   //entire source object on the stack (can be quite expensive for 
   //complex object types)

   //the 'byReference' parameter will be passed by creating a 
   //copy of the source pointer on the stack and setting it to 
   //point to the source object in memory
}

#3


1  

In C++, a variable is the variable that it is representing. It is the actual object in memory, at the actual location.

在c++中,变量是它表示的变量。它是内存中的实际对象,在实际位置。

However, you can choose to make such a variable represent a pointer instead, in which case it'll say "Hey, I'm me, I am pointing over there! The object you want isn't here, it's THERE. Yes, there! Go on, get there!".

但是,您可以选择使这样一个变量表示指针,在这种情况下,它会说“嘿,我是我,我指向那边!”你想要的东西不在这里,它在那里。是的,在那里!继续,到达那里!”。

Unless you're explicitly using C++'s "reference type", which I suspect you're not, then ALL arguments you pass are by value.

除非您明确使用c++的“引用类型”,我怀疑您不是这样的,那么您传递的所有参数都是有值的。

#4


0  

The answers to the questions in your second and third paragraph are both "yes". More specifically, if you pass an object to a function by value, the function will receive a copy of that object (created by the copy constructor).

第二段和第三段中问题的答案都是“是”。更具体地说,如果您按值将一个对象传递给一个函数,该函数将接收该对象的副本(由复制构造函数创建)。

#5


0  

When you pass an object to a function by value, it's copied by means of its class's copy constructor. If you haven't defined a copy constructor, there'll be a default one supplied by the compiler (unless you take special steps to avoid that), which is equivalent to copying the members by hand.

当您按值将一个对象传递给一个函数时,它将通过其类的复制构造函数进行复制。如果您还没有定义复制构造函数,那么编译器将提供一个默认构造函数(除非您采取特殊步骤避免这种情况),这相当于手工复制成员。

The preferred thing to do is often actually to pass a const reference rather than either a pointer or the object itself.

首选的做法通常是传递const引用,而不是传递指针或对象本身。

(You might want to be aware that actually a struct is just a class whose members are public by default; in particular, structs can have user-defined copy constructors too. A struct is not necessarily just plain inert data.)

(您可能想知道,实际上struct是一个类,其成员是默认为公共的;特别是,结构也可以有用户定义的复制构造函数。结构并不一定只是简单的惰性数据。

#6


0  

You have that right.

你是正确的。

Indeed, that's how it works. A pointer stores the memory address of a variable.

事实上,这就是它的工作原理。指针存储变量的内存地址。

When you pass a pointer (to an object) for a function as a parameter, it means that function will have access to that object through it's memory address instead of a new object being created on the stack.

当您将一个函数的指针(指向对象)传递给一个函数作为参数时,它意味着函数将通过它的内存地址来访问该对象,而不是在堆栈上创建一个新对象。

Check this thread for more info on pointers.

检查这个线程更多关于指针的信息。

#1


15  

It's exactly as you said.

正如你所说的。

When you pass an object by value, its copy constructor is invoked to produce a new instance of such object that will be used inside the function. The changes done to such new object won't be reflected to the original one1.

当您按值传递一个对象时,将调用其复制构造函数来生成该对象的新实例,该实例将用于函数内。对这种新对象所做的更改不会反映到原始对象1。

As with structures, the default copy constructor just does a shallow copy of the original object - i.e., its fields are copied2 to the new instance; in many cases this is not desirable (e.g. if the object wraps a pointer/another resource), so there are classes which redefine the copy constructor or disable it completely. Objects of these last classes can only be passed by pointer or reference.

与结构一样,默认的复制构造函数只对原始对象做一个浅拷贝——即。,其字段复制到新实例;在许多情况下,这是不可取的(例如,如果对象包装一个指针/另一个资源),所以有一些类重新定义复制构造函数或完全禁用它。这些最后类的对象只能通过指针或引用传递。

Passing objects by value can be costly if they are bigger than a pointer (in size) or in general if their copy constructor isn't "cheap". On the other hand, in comparison to pointers, the pass-by-value yields the usual advantages of not having to specify the pointer ownership, letting the callee do whatever it wants with the object, etc.

如果对象的值大于指针(大小),或者一般情况下,如果它们的复制构造函数不“便宜”,那么通过值传递对象的代价可能很高。另一方面,与指针相比,按值传递产生了通常的优点,即不必指定指针所有权,让被调用者对对象做任何想做的事情,等等。

Notice that passing an object by value kills the polymorphism. This because a function receiving an object by value receives a statically typed object, with a precise size and type, so any attempt to pass an object of a derived class will result in object slicing (the copy constructor for the base class is called, that by default just copies the fields that are available in the base class).

注意,按值传递对象会杀死多态性。这是因为一个函数接收一个对象的值接收一个静态类型的对象,具有精确的尺寸和类型,所以任何试图通过一个派生类的对象将导致对象切片(调用基类的拷贝构造函数,默认情况下只复制基类中的字段可用)。

This is the reason why often the preferred method of passing objects is by const reference. This yields several advantages:

这就是为什么通常首选的传递对象的方法是使用const引用的原因。这个收益率几个优势:

  • no copies involved; the object that the callee will see will be exactly the one specified at the moment of the call;
  • 涉及任何副本;被调用者将看到的对象将与调用时指定的对象完全相同;
  • no changes to the original object can be made, thanks to the const qualifier;
  • 由于const限定符,无法对原始对象进行更改;
  • if however the callee needs to change a copy of the object, it can still construct a copy by itself from the reference;
  • 但是,如果callee需要更改该对象的副本,它仍然可以从引用本身构造一个副本;
  • no awkward pointer syntax;
  • 没有尴尬的指针语法;
  • polymorphism preserved, since behind the scenes we're actually passing a pointer;
  • 多态性保留了下来,因为在幕后我们实际上传递一个指针;
  • no big doubts about object ownership: the general rule about references is that they are owned by the caller.
  • 关于对象所有权没有什么大的疑问:关于引用的一般规则是引用属于调用者。

  1. As far as the "raw fields" of the object are concerned; naturally if the original object and the copy continue to share a pointer/handle to the same resource some modifications to one may affect the other.

    关于对象的“原始字段”;自然,如果原始对象和副本继续共享同一资源的指针/句柄,某些修改可能会影响到另一个。

  2. Primitive types (and in general PODs) are copied bitwise, while the copy constructor is called for non-POD types.

    原始类型(在一般的pod中)按位复制,而复制构造函数用于非pod类型。

#2


3  

The difference mostly has to do with where in memory an object is allocated. For instance:

差异主要与在内存中分配对象的位置有关。例如:

int main() {
    MyObject x;   //allocates space for an instance of MyObject on the stack
    MyObject* y;  //allocates space for a pointer on the stack
    MyObject* z = new MyObject();  //allocates space for a pointer on the 
                                   //stack and an object instance in the heap and
                                   //sets the pointer to point to the new instance
    MyObject* a = &x;  //allocates space for a pointer on the stack and 
                       //makes it point to 'x'
    ...
}

int someFunc(MyObject byValue, MyObject* byReference) {
   //the 'byValue' parameter will be passed by creating a copy of the 
   //entire source object on the stack (can be quite expensive for 
   //complex object types)

   //the 'byReference' parameter will be passed by creating a 
   //copy of the source pointer on the stack and setting it to 
   //point to the source object in memory
}

#3


1  

In C++, a variable is the variable that it is representing. It is the actual object in memory, at the actual location.

在c++中,变量是它表示的变量。它是内存中的实际对象,在实际位置。

However, you can choose to make such a variable represent a pointer instead, in which case it'll say "Hey, I'm me, I am pointing over there! The object you want isn't here, it's THERE. Yes, there! Go on, get there!".

但是,您可以选择使这样一个变量表示指针,在这种情况下,它会说“嘿,我是我,我指向那边!”你想要的东西不在这里,它在那里。是的,在那里!继续,到达那里!”。

Unless you're explicitly using C++'s "reference type", which I suspect you're not, then ALL arguments you pass are by value.

除非您明确使用c++的“引用类型”,我怀疑您不是这样的,那么您传递的所有参数都是有值的。

#4


0  

The answers to the questions in your second and third paragraph are both "yes". More specifically, if you pass an object to a function by value, the function will receive a copy of that object (created by the copy constructor).

第二段和第三段中问题的答案都是“是”。更具体地说,如果您按值将一个对象传递给一个函数,该函数将接收该对象的副本(由复制构造函数创建)。

#5


0  

When you pass an object to a function by value, it's copied by means of its class's copy constructor. If you haven't defined a copy constructor, there'll be a default one supplied by the compiler (unless you take special steps to avoid that), which is equivalent to copying the members by hand.

当您按值将一个对象传递给一个函数时,它将通过其类的复制构造函数进行复制。如果您还没有定义复制构造函数,那么编译器将提供一个默认构造函数(除非您采取特殊步骤避免这种情况),这相当于手工复制成员。

The preferred thing to do is often actually to pass a const reference rather than either a pointer or the object itself.

首选的做法通常是传递const引用,而不是传递指针或对象本身。

(You might want to be aware that actually a struct is just a class whose members are public by default; in particular, structs can have user-defined copy constructors too. A struct is not necessarily just plain inert data.)

(您可能想知道,实际上struct是一个类,其成员是默认为公共的;特别是,结构也可以有用户定义的复制构造函数。结构并不一定只是简单的惰性数据。

#6


0  

You have that right.

你是正确的。

Indeed, that's how it works. A pointer stores the memory address of a variable.

事实上,这就是它的工作原理。指针存储变量的内存地址。

When you pass a pointer (to an object) for a function as a parameter, it means that function will have access to that object through it's memory address instead of a new object being created on the stack.

当您将一个函数的指针(指向对象)传递给一个函数作为参数时,它意味着函数将通过它的内存地址来访问该对象,而不是在堆栈上创建一个新对象。

Check this thread for more info on pointers.

检查这个线程更多关于指针的信息。