Sign in to follow this  
-JetSirus-

Thinking in CPP: Stash woes...

Recommended Posts

Ok, I have been reading and working my way through the Thinking in CPP book. It's acutally been pretty smooth. Or it was untill I got to the section where he makes a 'Stash' structure and explains it in sumerian. He doesn't actualy explain it in sumerian, just that he explains it really poorly. The Stash itself is used almost exactly like a vector. Im gonna post the code here and then describe what I think certain areas of significance are doing.
//: C04:CppLib.h
    // C-like library converted to C++

    struct Stash {
      int size;      // Size of each space
      int quantity;  // Number of storage spaces
      int next;      // Next empty space
       // Dynamically allocated array of bytes:
      unsigned char* storage;
      // Functions!
      void initialize(int size);
      void cleanup();
      int add(const void* element);
      void* fetch(int index);
      int count();
      void inflate(int increase);
    }; ///:~



int size Seems to mean the ammount of bytes each section holds. int quantity Quantity looks to be the number of entities stored in the Stash. int next I think 'next' holds the index number of the next free storage unit. unsigned char* storage This one is a real doozy. In english I would translate that as non-negative single character byte pointer, named storage. As to it's use? On a guess, I would assume it is used like a measuring stick. Each 'area' of storage size is defined by a number of these. If that's not right, and I don't think it is, I have NO CLUE. int add(const void* element) It returns an integer, that much I know. I am almost positive const is used to say "Hey! This variable never changes!". Now it gets hairy. A void pointer.. It's uses from the declaration defy me. I think it is basically saying that it does not know what type of pointer it will receive. Be it an integer or a double or whatever. void* fetch(int index); A void pointer function called fetch? Dubya tee eff... Obviously it's use is to get a value stored in it at the supplied index. I don't understand why he is declaring it as a void pointer though. On to the definintion section.. Fun!
    //: C04:CppLib.cpp {O}
    // C library converted to C++
    // Declare structure and functions:
    #include "CppLib.h"
    #include <iostream>
    #include <cassert>
    using namespace std;
    // Quantity of elements to add
    // when increasing storage:
    const int increment = 100;

    void Stash::initialize(int sz) {
      size = sz;
      quantity = 0;
      storage = 0;
      next = 0;
    }

    int Stash::add(const void* element) {
      if(next >= quantity) // Enough space left?
        inflate(increment);
      // Copy element into storage,
      // starting at next empty space:
      int startBytes = next * size;
      unsigned char* e = (unsigned char*)element;
      for(int i = 0; i < size; i++)
        storage[startBytes + i] = e[i];
      next++;
      return(next - 1); // Index number
    }

    void* Stash::fetch(int index) {
      // Check index boundaries:
      assert(0 <= index);
      if(index >= next)
        return 0; // To indicate the end
      // Produce pointer to desired element:
      return &(storage[index * size]);
    }

    int Stash::count() {
      return next; // Number of elements in CStash
    }

    void Stash::inflate(int increase) {
      assert(increase > 0);
      int newQuantity = quantity + increase;
      int newBytes = newQuantity * size;
      int oldBytes = quantity * size;
      unsigned char* b = new unsigned char[newBytes];
      for(int i = 0; i < oldBytes; i++)
        b[i] = storage[i]; // Copy old to new
      delete []storage; // Old storage
      storage = b; // Point to new memory
      quantity = newQuantity;
    }

    void Stash::cleanup() {
      if(storage != 0) {
        cout << "freeing storage" << endl;
        delete []storage;
      }
    } ///:~



Im not going over the whole thing, just the parts I obviously have no clue about.

void Stash::add(const void* element)

unsigned char* e = (unsigned char*)element; This gives me the fits. For one, there is some strange syntax used that he never explained when it assigned the char pointer e its value. Maybey he is type casting. To make things clear I am talking about the part after the = sign. When he puts '()' around unsigned char* is he type casting 'element'? storage[startBytes + i] = e[i]; Hold the boat.. It looks like he's using storage and e both like they are arrays.. Yet, they were not declared to be arrays.. *head spins* return(next - 1); Where is he returing this too? When you use the stash to add something you don't expect a value back. For example: myStash.add(myInt) That doesn't seem to imply its getting any kind of reply.

void* Stash::fetch(int index)

return &(storage[index * size]) There are two huge issues I have with this whole thing.. Firstly his seeming use of a void pointer function or method. Secondly, his odd syntax when returning things. The last one I think I get. He is returning the memory location of the value stored in the index specified of storage... Did I get it right? If that is the case, why not just make the function a non-pointer and return just the value of the index, not its memory location.

void Stash::inflate(int increase)

delete []storage; Why the brackets before the name? Don't they normally got at the rear? I think that's it for now. Sorry for such a long post dripping with n00b questions, but this book is starting to give me hives. [Edited by - -JetSirus- on July 20, 2006 4:20:58 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by -JetSirus-

void Stash::inflate(int increase)

delete []storage;
Why the brackets before the name? Don't they normally got at the rear?


When you make a new array such as
new char[1024],
it invokes operator new[]. This is decidedly not the same as operator new.

Therefor, when deleting something that was created with new[], it must similarly be deleted with delete[].

While you can call new[] by specifying
new typename[size],
when calling delete[], the brackets must go right after the word delete. ie:
delete[] typename

Note trying to delete[] an object created with new will cause problems, and trying to delete an object created with new[] will cause problems. Undefined behavior (really bad) problems.

(That, I do believe, is the most thoroughly unclear explanation I've ever attempted to give.)

Maybe its because its 2am, but the rest of your post confuses me.

Share this post


Link to post
Share on other sites
Quote:
Original post by Driv3MeFar
Quote:
Original post by -JetSirus-

void Stash::inflate(int increase)

delete []storage;
Why the brackets before the name? Don't they normally got at the rear?


When you make a new array such as
new char[1024],
it invokes operator new[]. This is decidedly not the same as operator new.

Therefor, when deleting something that was created with new[], it must similarly be deleted with delete[].

While you can call new[] by specifying
new typename[size],
when calling delete[], the brackets must go right after the word delete. ie:
delete[] typename

Ok, that kind of clears things up. Thanks.

Quote:
Maybe its because its 2am, but the rest of your post confuses me.
Join the club. The person that wrote that book is smart I will admit, but good lord on a popsicle does he move at a odd an undefined pace when teaching.

Share this post


Link to post
Share on other sites
It is a BIT of a confusing post, and I'm not sure anyone has the time to answer ALL of it (I don't at least) but I'll try to clarify one point:

Regarding pointers(*), arrays and delete [] name;

If you do int x[10]; I'm sure you are aware that creates an array of ten ints. What x (sort of) becomes is a pointer to the memory that the compiler allocates. It is not quite the same thing as a pointer but think of it that way for now. Thus you can do:


int x[10];

void f(int *p)
{
for(int i=0;i<10;++i) cout << p[i] << endl;
}

void g()
{
f(x);
}



to print the contents of the array. Now the above array is created statically in the program's data segment since it is global. If you declared the array inside a function, it would be created on the stack. In either case, x would be a pointer to the start of the allocated memory, and the [] syntax is really just shorthand for the pointer arithmetic needed to access a particular element, i.e:

x[4];

is shorthand for

*(x+4);

If you were to do:

int *x=new int[10];

you are manually creating your own array (on the heap) and again x becomes a pointer to the start of this memory and is otherwise used like the ones above. Because you created it manually, you have to delete it manually.

If you create a single int with

int *p=new int;

you delete it with

delete p;

BUT if you create an array of ints with

int *p=new int[10];

you have to delete it with the array-deleting syntax, which is

delete [] p;

This is a different kind of construct to declaring an array, and the brackets do indeed go BEFORE the name in this case.

I hope this clears up SOME of what you have asked [smile]. BTW, the class seems to be a bit of a C++ wrapper for C-style methods of programming, which may be why it is so intially confusing.

HTH Paul

Share this post


Link to post
Share on other sites
EasilyConfused
Thanks! That acutally helps alot. He never explains what he is actualy doing, just skims over the whys and then proceeds to wax philosophically for a while. Alot of people recommend this book, and it is great most of the time, but why oh why does he have to start mixing C with CPP on a topic he hasn't even went over yet.. ACK!

Share this post


Link to post
Share on other sites
After re-reading your post I think I kind of understand whats going on, but not really.

Let me get this straight first: This source code was given to you in the book, as well as some sumerian giberrish, and you have to what? Write a program that translates it?

As for a few of your questions:
Quote:

unsigned char* storage
This one is a real doozy. In english I would translate that as non-negative single character byte pointer, named storage. As to it's use? On a guess, I would assume it is used like a measuring stick. Each 'area' of storage size is defined by a number of these. If that's not right, and I don't think it is, I have NO CLUE.

This holds the actual item(s) in the stash. It is an unsigned char array because the size of an unsigned char is 1 byte, making it easy to work with. E.g., for an item of (size) size, you can just straight mem copy it into the array:
memcpy(storage[next], element, size);
and this will put the element sequentialy into memory, starting at byte (next) in the array.

Quote:

int add(const void* element)
It returns an integer, that much I know. I am almost positive const is used to say "Hey! This variable never changes!". Now it gets hairy. A void pointer.. It's uses from the declaration defy me. I think it is basically saying that it does not know what type of pointer it will receive. Be it an integer or a double or whatever.

This will add any arbitrary element, of any type (or at least (size) bytes of any object), into the stash. That is why its a void pointer. A void pointer basically is just a raw address into memory, and gives no information as to what type the object is it points at. This lets you add anything, rather than restricting your stash to say, only being able to store integers.

Take a look at the add code. It casts add to a unsigned char array first. As mentioned before, the size of an unsigned char is 1 byte, so its easy to work with when dealing with raw memory. Next, it adds your element, 1 byte at a time, into your storage. It does this for (size) bytes, since that is the size of your element.

Edit: thats a little unclear, so lets try again. Your void pointer gives your add function the address of the start of an element to add to storage. These elements are (size) bytes long. First, you cast to an unsigned char so you can work with 1 byte at a time. Next, you add the element, byte by byte, into storage. Since the function knows the length of your object in bytes (provided by the size data member), and the start of it in memory (provided by the void pointer), it places the entire thing into storage without ever needing to know what type the element actualy was.

Quote:

void* fetch(int index);
A void pointer function called fetch? Dubya tee eff... Obviously it's use is to get a value stored in it at the supplied index. I don't understand why he is declaring it as a void pointer though.


the reason for the void pointer here is the same as the reason for it in add. It looks to me like its basically a fugly way of templatizing your stash. Since the stash itself doesn't know what type of data it holds, it just grabs the start address of the object and returns it as a pointer. A pointer to what, its not sure (hence the void *). When, in your main app, you cast this pointer to something usefull, it will grab the appropriate number of bytes of data from storage, starting at the address given by fetch.

Share this post


Link to post
Share on other sites
Quote:
Original post by -JetSirus-
EasilyConfused
Thanks! That acutally helps alot. He never explains what he is actualy doing, just skims over the whys and then proceeds to wax philosophically for a while. Alot of people recommend this book, and it is great most of the time, but why oh why does he have to start mixing C with CPP on a topic he hasn't even went over yet.. ACK!


It is an unfortunately common phenomena that a lot of people still think that you should teach C first, then move up to C++. I think it is because a lot of people born in the 70s (like me *sob*) learned like that.

The point has been made very well many times (not least by the creator of C++) that it is not a prerequiste of knowing good C++ to learn C first and is in fact a lot easier to start with learning C++ constructs (std::vector, std::string) before trying to understand the C equivalents (arrays, raw memory, null-terminated strings).

The learning curve is faster and you write better, more robust code as a result.

Share this post


Link to post
Share on other sites
Quote:
Original post by Driv3MeFar
After re-reading your post I think I kind of understand whats going on, but not really.

Let me get this straight first: This source code was given to you in the book, as well as some sumerian giberrish, and you have to what? Write a program that translates it?
Heh sort of. The sumerian part was sarcasm. I meant that he explained it poorly, sorry. The stash is used almost exactly like a vector. Im gonna rework my initial post to clear some things up.

EDIT: Thanks for the info, sorry I failed to mention it earlier. This is some complex code to take in all at once, I will agree.

Share this post


Link to post
Share on other sites
Quote:
Original post by EasilyConfused
It is an unfortunately common phenomena that a lot of people still think that you should teach C first, then move up to C++. I think it is because a lot of people born in the 70s (like me *sob*) learned like that.

The point has been made very well many times (not least by the creator of C++) that it is not a prerequiste of knowing good C++ to learn C first and is in fact a lot easier to start with learning C++ constructs (std::vector, std::string) before trying to understand the C equivalents (arrays, raw memory, null-terminated strings).

The learning curve is faster and you write better, more robust code as a result.


I don't really mind learning some C. My problem is that he gives some really complex example of C converted to CPP then proceeds to use alot of concepts he hasn't even went over yet. Makes me want to stab somthings eye out.

Share this post


Link to post
Share on other sites
The book is aimed at people who know C; if that's not you, then of course you will have problems. It's not a beginners' book as such. If you have the 2nd edition then there is supposedly a quick-start chapter for C programming, but really you need to familiarise yourself with it first.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
The book is aimed at people who know C; if that's not you, then of course you will have problems. It's not a beginners' book as such. If you have the 2nd edition then there is supposedly a quick-start chapter for C programming, but really you need to familiarise yourself with it first.

Yea, I understood from the beginning of the book that he was aiming at people who knew a bit about C. It's just that some of this is moving a little fast. For the most part I have no trouble. And actually, just writing my post out made me understand ALOT of what was going on.. In fact I ended up deleting whole sections of the original post 3 times, because I understood what was going on by the end of the post.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this