class LinkedList
{
public:
LinkedList() : _head(nullptr) {}
LinkedList(ListElement *newElement) : _head(newElement) {}
~LinkedList() { };
LinkedList(const LinkedList& LL);
LinkedList& operator=(LinkedList byValLinkedList);
private:
ListElement *_head;
}
LinkedList::LinkedList(const LinkedList & LL)
{
ListElement *curr = LL._head;
// If Linked List is empty
if (isEmpty() && curr != nullptr) {
_head = new ListElement(curr->getValue());
curr = curr->getNext();
}
ListElement *newNode = nullptr;
while (curr) {
newNode = new ListElement(curr->getValue());
curr = curr->getNext();
}
}
LinkedList& LinkedList::operator=(LinkedList byValLinkedList)
{
std::swap(_head, byValLinkedList._head);
return *this;
}
int main() {
using namespace std;
LinkedList LL1(new ListElement(7));
//..... some insertions
LinkedList LL2(new ListElement(5));
//..... some insertions
LL1 = LL2; // What is the order ?
// ..... do something else
return 0;
}
执行LL1 = LL2时,应该调用哪一个。
我希望复制分配能够发生。但代码按以下顺序执行
- 复制构造函数
- 复制-Assignemnt
- 析构
醇>我做错了什么?为什么析构函数被称为?
答案 0 :(得分:1)
LinkedList& operator=(LinkedList byValLinkedList);
您的复制构造函数按值获取其参数。这意味着
LL1=LL2;
需要制作LL2
的副本,以便按值传递它。这就是“通过价值”的意思。因此,复制构造函数。
为避免进行复制构造,赋值运算符必须通过引用获取其参数,而不是:
LinkedList& operator=(const LinkedList &byValLinkedList);
这意味着,如果当然,您无法使用std::swap
完全实现赋值运算符。但这将是一个不同的问题......
简而言之,您有两个选择:实现两个复制构造函数,一个执行const
引用,另一个不执行,后者可以使用std::swap
。或者,将_head
声明为mutable
。
答案 1 :(得分:1)
你没有做错任何事,这正是复制和交换应该起作用的方式。
调用复制构造函数来设置参数,该参数由value传递。这太棒了,因为否则你的复制赋值操作符必须包含制作副本的代码。这样,您就可以在复制构造函数中重用逻辑。
然后,参数超出范围并在函数结束时被销毁。由于交换调用,该参数现在包含以前由*this
持有的资源。同样非常理想,因为析构函数负责释放它们 - 否则你必须为复制赋值操作符编写清理代码,以正确地去除被赋值所替换的数据。
除了代码重用之外,copy-and-swap还为您提供异常安全性。如果您将副本直接复制到左侧对象(*this
)中,那么如果出现任何问题,您已经丢失了旧值并且不能保持不变。但是使用copy-and-swap,复制构造函数首先完成它的工作 - 如果出现任何问题,例如内存不足,*this
保持其先前的值。
这里有关于复制和交换习语的非常广泛的解释:
答案 2 :(得分:0)
在赋值运算符中,byVallinkedList按值传递。通过使用复制构造函数
初始化LinkedList对象