Antwort und Beispiellösung

Content

Antwort zur Frage

Die Zuweisung old->next = nullptr; ist notwendig, weil sonst rekursiv die gesamte Liste freigegeben wird. Wir wollen aber nur das ganz oben liegende Objekt des Typs IntegerMember freigeben.

Beispiellösung

#include <cassert>
#include <iostream>

class IntegerMember {
   public:
      IntegerMember(int member, IntegerMember* next) :
	 member(member), next(next) {
      }
      IntegerMember(const IntegerMember& other) :
	 member(other.member),
	 next(
	    other.next?
	       new IntegerMember(*other.next)
	    :
	       nullptr
	 ) {
      }
      ~IntegerMember() {
	 delete next;
      }
      IntegerMember& operator=(const IntegerMember& other) {
	 delete next;
	 member = other.member;
	 if (other.next) {
	    next = new IntegerMember(*other.next);
	 } else {
	    next = nullptr;
	 }
	 return *this;
      }
      int member;
      IntegerMember* next;
};

class IntegerStack {
   public:
      IntegerStack() : top(nullptr) {
      }
      IntegerStack(const IntegerStack& other) :
	 top(
	    other.top?
	       new IntegerMember(*other.top)
	    :
	       nullptr
	 ) {
      }
      ~IntegerStack() {
	 delete top;
      }
      IntegerStack& operator=(const IntegerStack& other) {
	 delete top;
	 if (other.top) {
	    top = new IntegerMember(*other.top);
	 } else {
	    top = nullptr;
	 }
	 return *this;
      }
      void push(int member) {
	 top = new IntegerMember(member, top);
      }
      bool empty() {
	 return top == nullptr;
      }
      int pop() {
	 assert(top != nullptr);
	 int member = top->member;
	 IntegerMember* old = top;
	 top = top->next;
	 old->next = nullptr;
	 delete old;
	 return member;
      }
   private:
      IntegerMember* top;
};

void print(const char* name, IntegerStack& s) {
   std::cout << name << ":";
   while (!s.empty()) {
      std::cout << " " << s.pop();
   }
   std::cout << std::endl;
}

int main() {
   IntegerStack a; a.push(1); a.push(2); a.push(3);
   {
      IntegerStack b{a};
      print("b", b);
   }
   {
      IntegerStack c; c = a;
      print("c", c);
   }
   print("a", a);
}
heim$ diff -U 2 simple-stack2.cpp simple-stack-fixed.cpp
--- simple-stack2.cpp	2018-05-03 14:51:49.807947596 +0200
+++ simple-stack-fixed.cpp	2018-05-07 10:03:50.277913512 +0200
@@ -7,7 +7,26 @@
 	 member(member), next(next) {
       }
+      IntegerMember(const IntegerMember& other) :
+	 member(other.member),
+	 next(
+	    other.next?
+	       new IntegerMember(*other.next)
+	    :
+	       nullptr
+	 ) {
+      }
       ~IntegerMember() {
 	 delete next;
       }
+      IntegerMember& operator=(const IntegerMember& other) {
+	 delete next;
+	 member = other.member;
+	 if (other.next) {
+	    next = new IntegerMember(*other.next);
+	 } else {
+	    next = nullptr;
+	 }
+	 return *this;
+      }
       int member;
       IntegerMember* next;
@@ -18,7 +37,24 @@
       IntegerStack() : top(nullptr) {
       }
+      IntegerStack(const IntegerStack& other) :
+	 top(
+	    other.top?
+	       new IntegerMember(*other.top)
+	    :
+	       nullptr
+	 ) {
+      }
       ~IntegerStack() {
 	 delete top;
       }
+      IntegerStack& operator=(const IntegerStack& other) {
+	 delete top;
+	 if (other.top) {
+	    top = new IntegerMember(*other.top);
+	 } else {
+	    top = nullptr;
+	 }
+	 return *this;
+      }
       void push(int member) {
 	 top = new IntegerMember(member, top);
heim$ g++-7.2 -Wall -o simple-stack-fixed simple-stack-fixed.cpp
heim$ valgrind ./simple-stack-fixed
==15236== Memcheck, a memory error detector
==15236== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==15236== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==15236== Command: ./simple-stack-fixed
==15236== 
b: 3 2 1
c: 3 2 1
a: 3 2 1
==15236== 
==15236== HEAP SUMMARY:
==15236==     in use at exit: 72,704 bytes in 1 blocks
==15236==   total heap usage: 10 allocs, 9 frees, 72,848 bytes allocated
==15236== 
==15236== LEAK SUMMARY:
==15236==    definitely lost: 0 bytes in 0 blocks
==15236==    indirectly lost: 0 bytes in 0 blocks
==15236==      possibly lost: 0 bytes in 0 blocks
==15236==    still reachable: 72,704 bytes in 1 blocks
==15236==         suppressed: 0 bytes in 0 blocks
==15236== Rerun with --leak-check=full to see details of leaked memory
==15236== 
==15236== For counts of detected and suppressed errors, rerun with: -v
==15236== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
heim$