用C ++分配对象

时间:2013-11-12 01:47:34

标签: c++ object variable-assignment assign

要对我的问题进行语境化,我正在使用具有以下定义的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

现在接受以下两个代码段:

首先:

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

第二

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

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

4 个答案:

答案 0 :(得分:24)

这有点复杂。

考虑这个简单的类:

class Thing1
{
public:
  int n;
}

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

Thing1 A;
A.n = 5;

Thing1 B = A;
B.n = 7;

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

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

第二次实验:

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

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

结果是“9 9”; p是指向A的指针,因此A.np->n是相同的。

现在事情变得复杂了:

class Thing2
{
public:
  int *p;
};

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

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

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

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

编辑:感谢@AlisherKassymov,指出表单Thing A=B;的声明使用复制构造函数,而不是赋值运算符。 因此,要使解决方案适用于上述代码,复制构造函数必须进行深层复制。 (请注意,如果复制构造函数执行它,您几乎肯定希望赋值运算符也这样做(请参阅Rule of Three)。另请注意,如果这些函数变得复杂,只需让复制构造函数调用就可以了赋值运算符。)

答案 1 :(得分:5)

这两者并不相等。

第一个代码段

Matrix test,已将完整内容复制到Matrix ptr。 当您稍后使用ptr时,您只会更改副本,而不是原始Matrix test

第二个代码段

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

在Java中

在java中,所有对象都是指针(像int这样的基元不是)。当您将一个对象分配给另一个对象时,默认情况下仅覆盖指针值。就像你的第二个例子一样。

答案 2 :(得分:2)

第一个将test的值复制到ptr。 第二个将ptr设置为指向test

地址的指针

这两个动作并不相同。在第一种情况下,ptr将与test具有相同的值,但它们在其中包含两个不同的数据副本,因此ptr(0,0) = 95;的分配不会设置{{ 1}}。

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

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

test(0, 0)

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

答案 3 :(得分:1)

在这种情况下,Java行为的等效表达式使用C ++ references

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

此代码确实与指针版本完全相同,即它修改了原始test对象。

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

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