Stos przechowujący tablicę wskaźników do obiektów, THICPP rozdział 7

0

Witajcie! Po raz kolejny mam problem z wykonaniem jednego z ćwiczeń, jego treść brzmi:
[quote]
Utwórz nową wersję klasy Stack, zawierającą domyślny konstruktor, a także drugi konstruktor, przyjmujący jako argumenty tablicę wskaźników do obiektów oraz wielkość tablicy. Konstruktor powinien przejść przez tę tablicę, umieszczając na stosie każdy z zawartych w niej wskaźników. Przetestuj klasę, używając tablicę łańcuchów
[/quote]
Tutaj moja wariacja (niedziałająca) na ten temat:

main:

#include "Stack.h"
#include "require.h"
#include <fstream>
#include <iostream>
#include <string>
#include "Hen.h"
#include <cstdio>
using namespace std;

int main(void) {

  string tab[4]{"Wlazl", "kotek", "na" ,"plotek"};
  void * ptab[4];
  for(int i=0; i<4; i++)
    ptab[i]=(void*)&tab[i];
  cout<<"ETAP1COMPL\n\n\n";
  Stack container(ptab, 4);
  cout<<"ETAP2COMPL\n\n\n";

  string * sp;
  while((sp=(string*)container.pop())!=0)
  {
    cout<<*sp<<" ";
    delete sp;
  }
  return 0;
}

stack.cpp:

#include "Stack.h"
#include "require.h"
#include <iostream>
using namespace std;

void
Stack::Link::initialize(void* dat, Link* nxt) {
  data = dat;
  next = nxt;
}

Stack::Stack() { head = 0; }
Stack::Stack(void * tab[], int sizer)
{
    head=0;
    for(;sizer>0; sizer--){
        push(new void * (tab[sizer]));
        cout<<1;
        }
}

void Stack::push(void* dat) {
  Link* newLink = new Link;
  newLink->initialize(dat, head);
  head = newLink;
}

void* Stack::peek() {
  require(head != 0, "Stack empty");
  return head->data;
}

void* Stack::pop() {
  if(head == 0) return 0;
  void* result = head->data;
  Link* oldHead = head;
  head = head->next;
  delete oldHead;
  return result;
}

Stack::~Stack() {
  require(head == 0, "Stack not empty");
}

stack.h

#ifndef STACK2_H
#define STACK2_H

class Stack {
  struct Link {
    void* data;
    Link* next;
    void initialize(void* dat, Link* nxt);
  }* head;
public:
  Stack();
  Stack(void * tab[], int sizer);
  void push(void* dat);
  void* peek();
  void* pop();
  ~Stack();
};
#endif

Gdzie popełniłem błąd i dlaczego?
Z góry dziękuję za pomoc

0

OK, zlalazłem dość proste rozwiązanie jednego z problemów:

#include "Stack.h"
#include "require.h"
#include <fstream>
#include <iostream>
#include <string>
#include "Hen.h"
#include <cstdio>
using namespace std;

int main(void) {

  string tab[4]{"Wlazl", "kotek", "na" ,"plotek"};
  void * ptab[4];
  for(int i=0; i<4; i++)
    ptab[i]=(void*)&tab[i];
  for(int i=0; i<4; i++)
    cout<<*(string*)ptab[i]<<endl;
  cout<<"ETAP1COMPL\n\n\n";
  Stack container(ptab, 4);
  cout<<"ETAP2COMPL\n\n\n";

  string * sp;
  while((sp=(string*)container.pop())!=0)
  {
    cout<<*sp<<" ";
    //delete sp;
  }

  return 0;
}

Niestety - gdy użyję delete sp(tj zabiorę wykomentowanie tego) program przestaje działać, otrzymuję komunikat "invalid pointer" i błędy od glibc.
Tylko nie mam pewności, czy powinienem móc usunąć to co znajduje się pod adresem przechowywanym przez sp - nie jest to obszar danych, który został przydzielony za pomocą narzędzia do dynamicznego przydziału pamięci. Powinienem zabrać tylko destruktor, czy program nadal działa źle?

0

for(;sizer>0; sizer--){ // sizer będzie miał wartości 4,3,2,1 - poczytaj o indeksacji tablic:
push(new void * (tab[sizer])); // new void * (tab[sizer]) - to jakaś abrakadabra, co chciałeś tym osiągnąć ?
void initialize(void* dat, Link* nxt); // czemu nie zrobić zwykłego konstruktora ?

0

Och, zapomniałem podać zmieniony fragment kodu:

Stack::Stack() { head = 0; }
Stack::Stack(void * tab[], int sizer)
{
    head=0;
    for(;sizer>0; sizer--){
        push(tab[sizer-1]);
        cout<<"TEXT";
        }
}

a funkcja initialize to pozostałość - ta klasa ciągnie się za mną od czasów, jak jeszcze była strukturą bez funkcji składowych, stąd po prostu widocznie została użyta jako niepotrzebny już element z przeszłości tej klasy.

Bardziej interesuje mnie, jak można, odpowiedź na pytanie zawarte w drugim poście.

0

Po tych zmianach to już powinno działać. Z tym że nie możesz usuwać tego adresu (delete sp;) ponieważ w tym momencie próbujesz zrobić coś ala:
string x;
delete &x;
Czyli zwolnić jako obszar dynamiczny fragment stosu, wiadomo że będzie protestować.
Generalnie możesz jedynie przechowywać te wskaźniki ponieważ nawet gdyby zrobiłeś te stringi dynamicznie:
string &tab[4]{*(new string("Wlazl")), *(new string("kotek")), (new string("na")) ,(new string("plotek"))};
to teoretycznie już możesz zastosować ten twój delete sp;
Ale wtedy i tak nie zadziała destruktor stringa i nie zwolni pamięci zajmowanej przez napis.
Jedyne rozwiązanie które widzę to auto_ptr

1 użytkowników online, w tym zalogowanych: 0, gości: 1