Mainly looking for feedback on my use of smart pointers to implement a standard stack. For interview level production code I have also include a namespace and asserts to test my class, let me know if that would be appropriate for an interview. I'd like feedback on my pointer management to avoid memory leaks, like how I have the option to use the classic SomeObjectNameHere*
pointer to swap data in my swap
function or the unique_ptr
swap method.
Other than that I have taken feedback from all my previous posts to properly. Let me know what you think
#include <cassert>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
namespace sonsprl
{
class Stack
{
private:
class Node
{ private:
int m_data;
std::unique_ptr<Node> m_previous;
public:
Node(int data, std::unique_ptr<Node>& previous) {
m_data = data;
m_previous = std::move(previous);
}
~Node() { m_previous.reset(); }
const int data() { return m_data; }
std::unique_ptr<Node>& previous() { return m_previous; }
};
int m_size{0};
std::unique_ptr<Node> m_top;
public:
~Stack() { m_top.reset(); }
void push_back(int data) {
m_top = std::unique_ptr<Node>(new Node(data, m_top));
++m_size;
}
void pop_back() {
if(!m_top) {
throw std::out_of_range("ERROR: Can not pop. Stack empty.");
}
else {
m_top = std::move(m_top->previous());
--m_size;
}
}
int top() {
return m_top.get()->data();
}
int size() {
return m_size;
}
bool empty() {
return (m_size == 0) ? true : false;
}
void swap(Stack& other_stack) {
m_top.swap(other_stack.m_top);
// Node* other_top = other_stack.m_top.release();
// other_stack.m_top = std::move(m_top);
// m_top = std::unique_ptr<Node>(new Node(other_top->data(), other_top->previous()));
}
friend std::ostream& operator<<(std::ostream& os, Stack& stack) {
std::string stack_string = "";
Node* current = stack.m_top.get();
for(; current; current = current->previous().get()) {
stack_string = stack_string + '|' + std::to_string(current->data()) + '|' + '\n';
}
os << stack_string;
os << "---\n";
return os;
}
};
}
int main()
{
sonsprl::Stack stack;
try {
stack.pop_back();
} catch(const std::out_of_range& e) {
std::cout << e.what() << '\n';
}
assert(stack.empty());
stack.push_back(1);
stack.push_back(2);
stack.push_back(3);
assert(stack.size() == 3);
assert(stack.top() == 3);
stack.pop_back();
stack.pop_back();
assert(stack.size() == 1);
std::cout << stack << '\n';
stack.push_back(4);
stack.push_back(4);
assert(stack.empty() == false);
sonsprl::Stack swap_stack;
swap_stack.push_back(5);
swap_stack.push_back(6);
swap_stack.push_back(7);
swap_stack.push_back(8);
assert(swap_stack.top() == 8);
std::cout << "pre swap\n";
std::cout << stack << '\n';
std::cout << swap_stack << '\n';
swap_stack.swap(stack);
std::cout << "post swap\n";
std::cout << stack << '\n';
std::cout << swap_stack << '\n';
assert(stack.top() == 8);
assert(swap_stack.top() == 4);
std::cout << "passed all stack tests :) \n";
return 0;
}