默认赋值运算符=在c ++中是浅拷贝?

Chr*_*ian 38 c++ operators shallow-copy

只是一个简单的快速问题,我无法找到其他任何地方的可靠答案.默认运算符=只是右侧所有类成员的浅表副本吗?

Class foo {
public:
  int a, b, c;
};

foo f1, f2;
...
f1 = f2;
Run Code Online (Sandbox Code Playgroud)

将与以下内容相同:

f1.a = f2.a;
f1.b = f2.b;
f1.c = f2.c;
Run Code Online (Sandbox Code Playgroud)

当我测试它时,这似乎是真的,但我需要确定我没有错过某些特定情况.

Ste*_*sop 37

我会说,默认operator=副本.它复制每个成员.

除非被复制的成员是某种间接(例如指针),否则不会出现浅拷贝和深拷贝之间的区别.就默认operator=而言,由复制的成员决定"复制"的含义,它可以是深或浅的.

但是,具体来说,复制原始指针只是复制指针值,它对referand没有任何作用.因此,默认情况下,包含指针成员的对象被浅层复制operator=.

编写在复制时执行克隆操作的智能指针有各种各样的工作,所以如果你用它们来代替原始指针那么默认operator=将执行深层复制.

如果你的对象有任何标准容器作为成员,那么(例如)Java程序员说这operator=是一个"浅拷贝" 可能会让人感到困惑.在Java中,Vector成员实际上只是一个引用,因此"浅拷贝"意味着Vector不会克隆成员:源和目标引用相同的底层矢量对象.在C++中,vector成员与其内容一起被复制,因为成员是实际对象而不是引用(并vector::operator=保证使用它复制内容).

如果您的数据成员是指针的向量,那么您没有深拷贝浅拷贝.您有一个半深拷贝,其中源和目标对象具有单独的向量,但每个对应的向量元素仍指向相同的未克隆对象.


Naw*_*waz 14

是的,默认operator=是浅拷贝.

顺便说一句,在实际之间的差异shallow copy,并deep copy当类有变得可见指针作为成员字段.在没有指针的情况下,没有区别(据我所知)!

要了解它们之间的区别,请参阅以下主题(在stackoverflow本身上):


Mar*_*k B 9

是的,它只是成员复制对象,这可能会导致原始指针出现问题.


小智 7

"浅"与"深"复制在C++中的意义不如在C或Java中有意义.

为了说明这一点,我把你的Foo班级从三个int改为一个int,一个int*和一个vector<int>:

#include <iostream>
#include <vector>

class Foo {
public:
  int a;
  int *b;
  std::vector<int> c;
};

using namespace std;

int main() {
  Foo f1, f2;
  f1.a = 42;
  f1.b = new int(42);
  f1.c.push_back(42);
  f2 = f1;

  cout << "f1.b: " << f1.b << " &f1.c[0]: " << &f1.c[0] << endl;
  cout << "f2.b: " << f2.b << " &f2.c[0]: " << &f2.c[0] << endl;
}
Run Code Online (Sandbox Code Playgroud)

运行此程序时,它会产生以下输出:

f1.b: 0x100100080 &f1.c[0]: 0x100100090
f2.b: 0x100100080 &f2.c[0]: 0x1001000a0
Run Code Online (Sandbox Code Playgroud)

int很无聊,所以我把它留了下来.但是看看int*和之间的区别vector<int>:int*f1和f2是一样的; 这就是你所说的"浅层副本".的vector<int>但是是f1和f2之间不同; 这就是你所谓的"深层复制".

这里实际发生的operator =C++ 中的默认行为就好像它operator =的所有成员按顺序调用一样.在operator =intS,int*S,和其他原始类型只是逐字节浅拷贝.该operator =用于vector<T>执行深层复制.

所以我想说问题的答案是,不,C++中的默认赋值运算符不执行浅拷贝.但它也没有执行深层复制.C++中的默认赋值运算符以递归方式应用类成员的赋值运算符.


fab*_*ian 5

我个人喜欢Accelerated c++中的解释。文字(第201页)说:

如果类作者未指定赋值运算符,编译器将合成默认版本。默认版本被定义为递归操作 - 根据该元素类型的适当规则分配每个数据元素。类类型的每个成员都是通过调用该成员的赋值运算符来分配的。内置类型的成员是通过分配其值来分配的。

由于问题中的成员是整数,我知道它们是深度复制的。以下对您的示例的改编说明了这一点:

#include<iostream>
class foo {
public:
  int a, b, c;
};

int main() {
    foo f1, f2;
    f1 = f2;
    std::cout << "f1.a and f2.a are: " << f1.a << " and " << f2.a << std::endl;
    f2.a = 0;
    std::cout << "now, f1.a and f2.a are: " << f1.a << " and " << f2.a << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

打印:

f1.a and f2.a are: 21861 and 21861
now, f1.a and f2.a are: 21861 and 0
Run Code Online (Sandbox Code Playgroud)