所以我很快就参加了考试,并且仔细观察了我的笔记,老师说浅层副本被定义为一点一滴的副本。我知道关于浅拷贝和深拷贝的所有内容,但我不知道一点一滴的副本应该是什么意思。是不是所有的计算机数据都存储为位?这个定义是否意味着在浅拷贝期间,在复制数据时会实现比特流?有人知道这个“一点一滴”的术语吗?感谢
答案 0 :(得分:1)
假设您有两个变量MyObj a, b;
。如果a = b
执行浅拷贝,那么变量b
中的位现在将与变量a
中的位相同。特别是,如果MyObj
包含任何指针或引用,则a
和b
中的指针或引用都相同。指向或引用的对象不会被复制。
答案 1 :(得分:0)
以指针指向一大块数据为例:
int* my_ints = new int[1000];
my_ints
指向一个跨越一千int
秒的记忆区域的开始。
当你这样做时
int* his_ints = my_ints;
my_ints
的值被复制到his_ints
,即my_ints
的位被复制到his_ints
。这意味着his_ints
也指向my_ints
也指向同一内存区域的开头。因此,通过做
his_ints[0] = 42;
my_ints[0]
也将是42
,因为它们都指向相同的数据。这就是你的教授最有可能被称为“一点一滴”的复制,这通常也被称为“浅拷贝”。这在复制指针和引用时经常遇到(你不能在技术上复制引用,但是你可以绑定对绑定到另一个引用的变量的引用)。
现在,您可能不希望逐位复制行为。例如,如果您想要一个副本,并且想要修改该副本而不修改源。为此,您需要进行深层复制。
int* my_ints = new int[1000];
int* his_ints = new int[1000];
std::copy(my_ints, my_ints + 1000, his_ints);
std::copy
将int
指向my_ints
指向的内存区域中的his_ints
复制到my_ints[0] = 42;
his_ints[0] = 90;
指向的内存区域。现在,如果你这样做
my_ints[0]
his_ints[0]
和class Example {
public:
int* data;
Example() {
data = new int[1000];
}
Example(const Example&) = default; // Using C++11 default specifier
~Example() {
delete[] data;
}
};
// Example usage
{
Example x;
Example y = x; // Shallow copies x into y
assert(x.data == y.data);
// y's destructor will be called, doing delete[] data.
// x's destructor will be called, doing delete[] data;
// This is problematic, as you are doing delete[] twice on the same data.
}
现在会有不同的值,因为它们现在指向各自不同的记忆区域。
当你拥有C ++类时,你应该正确定义它的构造函数。与主题相关的一个构造函数是复制构造函数(注意:这也适用于复制赋值运算符)。如果您只让编译器生成默认的复制构造函数,它只会执行数据的浅表副本,包括可能指向内存区域的指针。
Example(const Example& rhs) {
data = new int[1000];
std::copy(data, data + 1000, rhs.data);
}
要解决此问题,您必须执行数据的深层复制。要完成此操作,您必须自己定义复制构造函数。
{{1}}
有关详细信息和更好的说明,请参阅What is The Rule of Three?。
答案 2 :(得分:0)
我会将逐位副本定义为将分配给对象的信息作为非结构化内存块传输。在简单结构的情况下,这很容易想象。
源结构的内容是什么?他们初始化了吗?它与其他物体的关系是什么?一切都不重要。
在某种意义上,逐位复制就像一个浅拷贝,就像浅拷贝一样,逐位拷贝不会复制相关对象,但这是因为它甚至不考虑对象关系。
例如,C ++将trivial copy constructor定义为
普通的复制构造函数是一个构造函数,它创建参数的对象表示的按字节副本,而不执行任何其他操作。具有普通拷贝构造器的对象可以通过手动复制它们的对象表示来复制,例如,与std :: memmove。所有与C语言兼容的数据类型(POD类型)都可以轻松复制。
相比之下,由于对象关系的问题,浅拷贝及其对应的深拷贝作为一个概念存在。