C++中对象的赋值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19919434/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:15:29  来源:igfitidea点击:

Assignment of objects in C++

c++objectvariable-assignmentassign

提问by user1493813

To contextualize my question, I'm using a Matrix class with the following definitions:

为了将我的问题上下文化,我使用了一个具有以下定义的 Matrix 类:

Matrix(unsigned int, unsigned int); // matrix of the given dimension full of zeroes
Matrix(Matrix*); // creates a new matrix from another one
int &operator()(int, int);  // used to access the matrix
int **matrix; // the matrix

Now take these two code snippets:

现在拿这两个代码片段:

First:

第一的:

Matrix test(4,4);
Matrix ptr = test;
ptr(0,0) = 95;

Second:

第二:

Matrix test(4,4);
Matrix *ptr = &test;
(*ptr)(0,0) = 95;

Both codes have the same effect, the element in the (0,0) position receives 95 (The first snippet is very similar to Java, the reason which led me to ask this question). The question is, are both ways correctly making the assignment of the object?

两个代码的效果相同,(0,0) 位置的元素接收 95(第一个片段与 Java 非常相似,导致我问这个问题的原因)。问题是,这两种方法都正确地分配了对象吗?

回答by Beta

This is a little complicated.

这有点复杂。

Consider this simple class:

考虑这个简单的类:

class Thing1
{
public:
  int n;
}

Now we try the first experiment:

现在我们尝试第一个实验:

Thing1 A;
A.n = 5;

Thing1 B = A;
B.n = 7;

cout << A.n << " " << B.n << endl;

The result is "5 7". Aand Bare two separate, independent objects. Changing one doesn't change the other.

结果是“5 7”。AB是两个独立的、独立的对象。改变一个不会改变另一个。

Second experiment:

第二个实验:

Thing1 *p = &A;
p->n = 9;

cout << A.n << " " << p->n << endl;

The result is "9 9"; pis a pointer to A, so A.nand p->nare the same thing.

结果是“9 9”;p是指向 的指针A,所以A.np->n是同一回事。

Now things get complicated:

现在事情变得复杂了:

class Thing2
{
public:
  int *p;
};

...
Thing2 A;
A.p = new int(2);

Thing2 B = A;
*(B.p) = 4;

cout << *(A.p) << " " << *(B.p) << endl;

Now the result is "4 4". The assignment B = Acopied the pointer, so although Aand Bare two different objects, their pointers point to the same int. This is a shallow copy. In general, if you want to make a deep copy(that is, each Thing points to an int of its own) you must either do it by hand or give the class an assignment operatorwhich will handle it. Since your Matrixclass doesn't have an explicit assignment operator, the compiler gives it the default-- which is a shallow copy. That's why, in your first snippet, both matrices appear to be changed.

现在的结果是“4 4”。赋值B = A复制了指针,因此虽然AB是两个不同的对象,但它们的指针指向同一个 int。这是一个浅拷贝。一般来说,如果你想制作一个深拷贝(也就是说,每个 Thing 都指向它自己的一个 int),你必须手动完成或者给类一个赋值运算符来处理它。由于您的Matrix类没有显式赋值运算符,编译器给它默认值——这是一个浅拷贝。这就是为什么在您的第一个片段中,两个矩阵似乎都发生了变化。

EDIT:Thanks to @AlisherKassymov, for pointing out that declarations of the form Thing A=B;use the copy constructor,not the assignment operator.So for the solution to work in the above code, the copy constructor must make a deep copy. (Note that if the copy constructor does it, you almost certainly want the assignment operator to do it too (see the Rule of Three). Also note that if these functions get complicated, it makes sense to simply have the copy constructor invoke the assignment operator.)

编辑:感谢@AlisherKassymov,指出表单的声明Thing A=B;使用复制构造函数,而不是赋值运算符。因此,对于在上述代码中工作的解决方案,复制构造函数必须进行深度复制。(请注意,如果复制构造函数执行此操作,您几乎肯定希望赋值运算符也执行此操作(请参阅三法则)。另外请注意,如果这些函数变得复杂,那么简单地让复制构造函数调用赋值操作是有意义的操作员。)

回答by Atle

These two are not equal.

这两者并不相等。

The first snippet

第一个片段

Matrix test, with is full content is COPIED into Matrix ptr. When you work with ptrlater, you only change the copy, not the original Matrix test.

Matrix test,与是完整的内容被复制到Matrix ptr. 当您ptr以后使用时,您只能更改副本,而不是原始Matrix test.

The second snippet

第二个片段

The address of Matrix testis put into the pointer Matrix *ptr. The pointer now holds the address of test. When you write (*ptr), you dereference the pointer and work with the value of the original test.

的地址Matrix test被放入指针中Matrix *ptr。指针现在保存 的地址test。编写时(*ptr),您取消引用指针并使用原始值test

In Java

在 Java 中

In java, all objects are kindof pointers (primitives like intare not). When you assign one object to another there, the default is to only overwrite the pointer value. Works like your second example.

在 java 中,所有对象都是某种指针(int不是的原始类型)。当您将一个对象分配给另一个对象时,默认值是仅覆盖指针值。像你的第二个例子一样工作。

回答by Sinkingpoint

The first copies that value of testinto ptr. The second sets ptr to be a pointer to the address of test

第一个将该值复制testptr. 第二个将 ptr 设置为指向以下地址的指针test

These two actions are not the same. In the first case, ptrwill have the same value as test, but they are in them selves two distinct copies of that data, so that your assignment of ptr(0,0) = 95;will not set test(0, 0).

这两个动作并不相同。在第一种情况下,ptr将与 具有相同的值test,但它们本身是该数据的两个不同副本,因此您的赋值ptr(0,0) = 95;不会设置test(0, 0)

In the second instance however, ptrpoints to the address of test, so that the dereference of ptristest. Thus, when you set the value here, you are actually setting the value of test(0, 0)as well.

然而,在第二个实例中,ptr指向 的地址test,因此取消引用的ptrtest。因此,当您在此处设置值时,您实际上也在设置 的值test(0, 0)

This is trivially verifyable with a program such as this:

这可以通过如下程序轻松验证:

#include <iostream>
class Test{
public:
    int i;
};

int main(){
    Test c;
    c.i = 1;

    Test d = c;
    d.i = 2;
    std::cout << "Value: " << c.i << "\n";

    Test* e = &c;
    (*e).i = 2;
    std::cout << "Pointer: " << c.i << "\n";
}

Of course, if you dynamically allocate your Matrix (new) then when you copy the value as per your first example, the pointer to the data is also copied, so when you set the new data, it appears to be equal to the second example.

当然,如果您动态分配矩阵(新),那么当您按照第一个示例复制值时,也会复制指向数据的指针,因此当您设置新数据时,它似乎等于第二个示例.

回答by AnT

The equivalent of Java behavior in this case is expressed using C++ references

在这种情况下,Java 行为的等价物使用 C++引用表示

Matrix test(4,4);
Matrix &ptr = test;
ptr(0,0) = 95;

This code indeed does the same thing as the pointer version, i.e. it modifies the original testobject.

这段代码确实与指针版本做同样的事情,即它修改原始test对象。

Your first code sample formally creates a copyof the original object and then modifies that copy. However, your Matrixclass appears to be a multi-level object that owns some lower-level memory (matrixpointer). If your Matrixclass copy constructor implements shallow-copying logic (i.e. it shares the lower-level matrix data with the original object instead of deep-copying it), then modifying the copy will appear to modify the original object as well. Whether this behavior is correct or incorrect depends on your intent.

您的第一个代码示例正式创建原始对象的副本,然后修改该副本。但是,您的Matrix类似乎是一个拥有一些低级内存(matrix指针)的多级对象。如果您的Matrix类复制构造函数实现了浅复制逻辑(即它与原始对象共享较低级别的矩阵数据而不是对其进行深复制),那么修改副本似乎也修改了原始对象。这种行为是正确还是错误取决于您的意图。

In your comments you mentioned that the first code also appears to modify the original object. This immediately means that your class in fact implements shallow-copying logic. And it looks like it is not an intended part of your design. Apparently you forgot to follow the Rule of Threewhen you were implementing your Matrixclass.

在您的评论中,您提到第一个代码似乎也修改了原始对象。这立即意味着您的类实际上实现了浅复制逻辑。看起来它不是您设计的预期部分。显然,您在实施课程时忘记了遵循三原则Matrix