when i release a library of code for example my "stack class" where should i put the exception handling code for it? for example...

should it be
stack.h
stack.cpp
stackExceptions.h
stackExceptions.cpp

or..... like this

stack.h <--- embed stack exception interface in here
stack.cpp <--- embed stack exception implementation in here

Also does anyone happen to have any type of resources that explain what should and shouldn't be in certain .cpp and .h files?

Normally it is done as follows:

//in stack.h

#ifndef STACK_H
#define STACK_H

//include whatever you need.
#include <exception>

namespace my_code { //put your stuff in a namespace of your choosing.

struct stack_full_failure : public std::exception {
  const char* what() const throw() {
    return "Stack is full!";
  };
};

template <typename T>
class stack {
  //... your implementation of stack.

  void push(const T& NewElement) {
    if(numElements == stackSize)     //if the stack is full
      throw stack_full_failure;      //throw your exception.
    data[numElements++] = NewElement;//else, add the element to the stack.
  };
};

};

#endif

Whether the code is in the header file or in the cpp file doesn't really matter (I mean the "standard" guidelines still apply: don't put too much code in the header, don't break the clarity of the code, if stack is templated you pretty much have to put the code in the header, etc.).

The custom exception classes that you might want to define (like stack_full_failure in my example) are basically part of the interface of your class, so it makes sense that they would reside in the same header file.

Also, for a real library, it makes sense to document things well, for example with doxygen tags:

/**
 * This exception class is thrown when an operation that requires growing a 
 * stack's size cannot be performed because it exceeds the stack's maximum 
 * capacity.
 */
struct stack_full_failure : public std::exception {
  //...
};
/**
 * This class implements ...
 */
template <typename T>
class stack {
  //...

  /**
   * This member function is used to push a new element on top of the stack. 
   * \param NewElement The new element to be put on top of the stack.
   * \throw stack_full_failure if the maximum capacity of the stack was already reached and the new element could not be pushed.
   */
  void push(const T& NewElement) {
    if(numElements == stackSize)     //if the stack is full
      throw stack_full_failure;      //throw your exception.
    data[numElements++] = NewElement;//else, add the element to the stack.
  };
};

As for the user side code, it could look something like this (the example just pushes and pops random amounts of elements):

int main() {
  std::srand((unsigned int)std::time(0));
  using namespace my_code;

  stack<int> pile_of_ints;

  try {
    for(int i=0;i<1000;++i) {
      int m = rand() % 10;      //some random number less than 10.
      for(int j=0;j<m;++j)
        pile_of_ints.push(rand() % 1000); //push m elements with random value.
      m = rand() % 10;
      for(int j=0;j<m;++j)
        pile_of_ints.pop();      //pop some random amount of elements.
    };
  } catch(stack_full_failure& e) {
    std::cout << "Could not do all the random shit I wanted because the stack complained with '" << e.what() << "'." << std::endl;
  };
  std::cout << "This random program succeeded!" << std::endl;
  return 0;
};
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.