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.000000000 +0200
+++ simple-stack-fixed.cpp	2018-05-07 10:03:50.000000000 +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++-8.3 -Wall -g -o simple-stack-fixed simple-stack-fixed.cpp
heim$ valgrind ./simple-stack-fixed
==30318== Memcheck, a memory error detector
==30318== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==30318== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==30318== Command: ./simple-stack-fixed
==30318== 
b: 3 2 1
c: 3 2 1
a: 3 2 1
==30318== 
==30318== HEAP SUMMARY:
==30318==     in use at exit: 0 bytes in 0 blocks
==30318==   total heap usage: 11 allocs, 11 frees, 76,944 bytes allocated
==30318== 
==30318== All heap blocks were freed -- no leaks are possible
==30318== 
==30318== For counts of detected and suppressed errors, rerun with: -v
==30318== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
heim$