#include <iostream>
using namespace std;
#define OUT(x) cout << (x) << endl;

template<class T, int size> class Stack{
	T arr[size];
	int top;
public:
	Stack():top(-1){}
	void push(T obj);
	T pop();
};
template<class T, int size> void Stack<T,size>::push(T obj){
	top++;
	if(top >= size){
		top--;
		OUT("the stack is full");
	}else{
		arr[top] = obj;
	}
}
template<class T, int size> T Stack<T,size>::pop(){
	if(top < 0){
		OUT("the stack is empty");
		return NULL;
	}else{
		T obj = arr[top];
		arr[top] == NULL;
		top--;
		return obj;
	}
}

int main() {
	Stack<int, 5> intStack;
	for(int i = 0; i < 5; i++)
		intStack.push(i);
	for(int i = 0; i < 5; i++)
		OUT(intStack.pop())

	return 0;
}

The code above works fine without any compile time or runtime errors, but when i add this to the main function:

Stack<string, 5> strStack;
for(int i = 0; i < 5; i++)
	strStack.push("hello");
for(int i = 0; i < 5; i++)
	OUT(strStack.pop())

and when i compile the code, it gives me these error messages:
(i test this on eclipse)

make all
Building file: ../src/Stack.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/Stack.d" -MT"src/Stack.d" -o"src/Stack.o" "../src/Stack.cpp"
../src/Stack.cpp: In member function ‘T Stack<T, size>::pop() [with T = int, int size = 5]’:
../src/Stack.cpp:39: instantiated from here
../src/Stack.cpp:28: warning: NULL used in arithmetic
../src/Stack.cpp:28: warning: statement has no effect
../src/Stack.cpp: In member function ‘T Stack<T, size>::pop() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int size = 5]’:
../src/Stack.cpp:45: instantiated from here
../src/Stack.cpp:28: error: no match for ‘operator==’ in ‘((Stack<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 5>*)this)->Stack<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 5>::arr[((Stack<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 5>*)this)->Stack<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 5>::top] == 0’
make: *** [src/Stack.o] Error 1

Start by including the <string> header, which you failed to do. Also note that NULL isn't a compatible type with std::string; your stack class makes unwarranted assumptions about the type of T. Instead of NULL, you can generally use T() safely as a default value, though it's usually a better idea to design your class so as to not need a default value.

Thank you for your reply,

When I change this line arr[top] == NULL; to arr[top] == T(); , it just works. but this seems not being what I wanted, I wanted to assign a "null" value to the array element, T() does not produce a "null" value, right? I mean "null", something we find in Java. is there an equivalent in C++?

...though it's usually a better idea to design your class so as to not need a default value.

It's not so easily to design an intrusive container class for elements without default constructor (no underlying arrays, for example).

>T() does not produce a "null" value, right?
It produces a default constructed object for the type. In the case of std::string, it's an empty string.

>I wanted to assign a "null" value to the array element
Assigning "null" doesn't do anything meaningful in this case. What are you trying to accomplish?

>is there an equivalent in C++?
It depends on what you want to do. If you're worried about any of the cases where setting to "null" is useful, you've got fundamental design issues to iron out first. Personally, I don't see why it can't be as simple as this for your class:

#include <iostream>
#include <exception>
#include <stdexcept>
#include <string>

using namespace std;

template <class T, int size>
class Stack {
  T arr[size];
  int top;
public:
  Stack(): top(0) {}
  void push ( T obj );
  T pop();
};

template <class T, int size>
void Stack<T,size>::push ( T obj )
{
  if ( top >= size )
    throw runtime_error ( "Stack is full" );

  arr[top++] = obj;
}

template <class T, int size>
T Stack<T,size>::pop()
{
  if ( top == 0 )
    throw runtime_error ( "Stack is empty" );

  return arr[--top];
}

int main()
{
  Stack<string, 5> s;

  try {
    for ( int i = 0; i < 6; i++ )
      s.push ( "hello" );
  } catch ( exception& ex ) {
    cerr<< ex.what() <<'\n';
  }

  try {
    for ( int i = 0; i < 6; i++ )
      cout<< s.pop() <<'\n';
  } catch ( exception& ex ) {
    cerr<< ex.what() <<'\n';
  }
}

>It's not so easily to design an intrusive container class
>for elements without default constructor
Either you misunderstood what I said, or I have no idea what point you're trying to make.

It produces a default constructed object for the type. In the case of std::string, it's an empty string.

so the default constructed object of string class does not take storage? this is what I care about, when I pop an element out of the Stack, I don't want that element to still take memory storage.

>so the default constructed object of string class does not take storage?
It's an empty string, for whatever that means on your system. Most likely that means the base size for the object and no wasted dynamic memory.

>when I pop an element out of the Stack, I don't
>want that element to still take memory storage.
My advice is not to worry about it. But setting the item to T() is the most portable way to hopefully do what you want, if you're lucky. Will it work? Maybe, maybe not, depending on the type of T and how much extra dynamic memory it uses for the default construction. Will it hurt? Maybe, maybe not, also depending on the type of T and how it handles memory.

There's just so much involved that unless you've done this before and have a good idea of how things will work, my advice once again is not to worry about it.

Narue, Thank you so much!
Now the confusion in my head has been cleared.
Thank you!

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.