0

我不明白为什么他们没有一个复制构造函数,它使原始的真正倍数。

我们知道默认复制构造函数的主要问题是,它执行的是浅拷贝。因此,如果有一个指针,它只会复制它的地址,但为什么不取消引用指针 a 复制内容?主要问题出现在动态分配内存时。因此,当指针指向它时,可能会错误地删除它,这就是我们制作自己的复制构造函数而不使用默认构造函数的原因。

但是我看不懂,为什么CPP不做呢?为什么不复制内容

4

3 回答 3

11

我们知道默认复制构造函数的主要问题是,它执行的是浅拷贝。

我们不知道。

这就是我们制作自己的复制构造函数而不使用默认构造函数的原因。

在 C++ 中,您几乎不应该编写自己的复制构造函数(零规则)。

主要问题出现在动态分配内存时。这样人们就可以在有一个指向它的指针时错误地删除它

这不是问题。为什么?因为在 C++ 中,我们使用RAII的概念,并且我们在标准库中有工具可以解决您看到的所有问题。在 C++ 中,您永远不必显式编写new,并且您永远不应该拥有作为所有者的原始指针。使用标准容器(例如std::vector)和智能指针,例如(std::unique_ptr)。

我不明白为什么他们没有一个复制构造函数,它是原始的倍数

因为编译器不知道对象的复制语义应该是什么。只有班上的作者才知道。你无法知道指针的语义是什么。是唯一拥有内存资源的指针吗?如果是这样,它是用malloc, new,new[]还是用其他东西获得的?它是否共享内存的所有权?或者它只是指向一个它不拥有的对象?由于您无法从类的声明/定义中知道任何这些,因此编译器根本无法使用原始指针自动实现“深拷贝”。

除了。它默认实现深拷贝,默认实现浅拷贝,或者它们的组合。它这样做是正确的。还记得我告诉过你不要使用原始指针作为所有权吗?使用适当的抽象(容器、智能指针),默认的复制 ctor 将完全完成它需要做的事情。

于 2019-10-10T02:02:58.070 回答
4

我们知道默认复制构造函数的主要问题是,它执行的是浅拷贝。

浅拷贝一般不是问题。如果您想进行深层复制,拥有引用成员并假设隐式复制构造函数可以执行您想要的操作,这只是一个问题。

浅拷贝通常很有用,而且通常是有意的。

但为什么它不取消引用指针 a 复制内容?

因为复制构造函数将复制的对象存储在哪里?指针成员应该指向哪里?

编译器无法读懂你的想法,也不知道你是否要分配内存,或者如何分配内存。如果编译器确实在隐式函数中分配了内存,那么谁将负责删除它?如果编译器隐式删除了任何指针,那么当您打算拥有指向不能删除的东西的非拥有指针时,这将是非常令人惊讶的。

为什么程序员不能对此负责?

内存管理本身就够难了。目前,它至少可以通过遵循简单的规则来管理:你拥有 delete所拥有的一切。如果我们引入隐式分配并将知道这些隐式分配存在的责任强加给程序员,我们的工作将变得更加困难。 new

此外,指针可能具有无效值。在这种情况下,通过它间接会产生未定义的行为。并且无法检查指针以确定它是否无效。这将使建议的隐式“深度复制”非常容易出错。

在具有手动内存管理的语言中,浅隐式复制是唯一明智的选择。即使在垃圾收集语言中,这通常也是更好的选择。

这就是我们制作自己的复制构造函数而不使用默认构造函数的原因。

我们很少编写用户声明的复制构造函数(在初学者课程之外)。这些主要用于其唯一目的是管理内存(或其他资源)的类,例如智能指针。而且我们很少需要编写这些,因为标准库提供了开箱即用的最通用的智能指针和数据结构。

一旦我们在类中有动态内存,我们应该创建自己的复制构造函数

实际上,如果您的类管理动态内存,那么它将需要一个自定义复制构造函数。但典型的解决方案是不在课堂内管理动态内存。见上段。将所有内存分配和其他动态资源保存在智能指针或容器中。

于 2019-10-10T02:10:28.143 回答
1

编译器无法知道它应该“深度复制”的指针的含义。

例如,浮点指针是指向单个浮点数还是指向 C 样式的浮点数数组?如果它是一个数组,它应该复制的数组的长度是多少?请注意,我不是在谈论 C++ 样式数组(即std::array)。

如果您希望自动处理“深度复制”,您可以将容器类用于应该复制的数据成员。

于 2019-10-10T02:21:37.593 回答