Improving C++ Encapsulation with the Pimpl Idiom: Listing 2
A message queue "pImpling" a primitive array.
/**********************************************
my_queue.h
**********************************************/
#include <memory>
#include <string>
using namespace std;
typedef string element_t;
class my_queue {
struct queue_impl; // forward-declared nested struct
unique_ptr<queue_impl> pImpl;
public:
my_queue();
my_queue(const my_queue&);
my_queue(my_queue&&);
size_t enqueue(const element_t&);
element_t dequeue();
size_t get_lenght() const;
bool is_empty() const;
my_queue& operator=(const my_queue&);
my_queue& operator=(my_queue&&);
~my_queue();
};
/**********************************************
my_queue.cpp
**********************************************/
#include "my_queue.h"
#include <stdexcept>
#include <algorithm>
#include <utility>
using namespace std;
const size_t ARRAY_LIMIT = 1000;
struct my_queue::queue_impl {
element_t* array;
size_t top, bottom;
queue_impl() : array{new element_t[ARRAY_LIMIT]}, top{0}, bottom{0} {}
~queue_impl() { delete[] array; }
};
my_queue::my_queue() : pImpl{new queue_impl{}} {}
my_queue::my_queue(const my_queue& other) : pImpl{new queue_impl{}} {
for (size_t i = other.pImpl->top;i<other.pImpl->bottom;++i)
enqueue(other.pImpl->array[i]);
}
my_queue::my_queue(my_queue&& other)=default;
size_t my_queue::enqueue(const element_t& e) {
if (pImpl->bottom < ARRAY_LIMIT)
pImpl->array[pImpl->bottom++] = e;
else
throw overflow_error("The queue ran out of space.");
return pImpl->bottom;
}
element_t my_queue::dequeue() {
if (pImpl->top == pImpl->bottom)
throw runtime_error("The queue is empty.");
if (pImpl->top > pImpl->bottom)
throw runtime_error("The queue is an inconsistent state.");
return pImpl->array[pImpl->top++];
}
size_t my_queue::get_lenght() const {
return pImpl->bottom - pImpl->top;
}
bool my_queue::is_empty() const {
return pImpl->top == pImpl->bottom;
}
my_queue& my_queue::operator=(const my_queue& other) {
if (this!=&other) {
pImpl->top = pImpl->bottom = 0;
for (size_t i = other.pImpl->top;i<other.pImpl->bottom;++i)
enqueue(other.pImpl->array[i]);
}
return *this;
}
my_queue& my_queue::operator=(my_queue&& other)=default;
my_queue::~my_queue()=default;
/**********************************************
main.cpp
**********************************************/
#include "my_queue.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
my_queue q1, q2;
element_t lincoln_quote[] = {
"Give", "me", "six", "hours", "to", "chop", "down", "a", "tree", "and",
"I", "will", "spend", "the", "first", "four", "sharpening", "the", "axe"
};
for (int i = 0; i<10; ++i)
q1.enqueue(lincoln_quote[i]);
for (int i = 0; i<5; ++i) {
cout << "Queue 1: " << (q1.dequeue()) << endl;
}
// prints
// Queue 1: Give
// Queue 1: me
// Queue 1: six
// Queue 1: hours
// Queue 1: to
q2 = q1;
for (int i = 10; i<19; ++i)
q1.enqueue(lincoln_quote[i]);
while (!q2.is_empty()) {
cout << "Queue 2: " << (q2.dequeue()) << endl;
}
// Queue 2: chop
// Queue 2: down
// Queue 2: a
// Queue 2: tree
// Queue 2: and
while (!q1.is_empty()) {
cout << "Queue 1: " << (q1.dequeue()) << endl;
}
// Queue 1: chop
// Queue 1: down
// Queue 1: a
// Queue 1: tree
// Queue 1: and
// Queue 1: I
// Queue 1: will
// Queue 1: spend
// Queue 1: the
// Queue 1: first
// Queue 1: four
// Queue 1: sharpening
// Queue 1: the
// Queue 1: axe
}
About the Author
Diego Dagum is a software architect and developer with more than 20 years of experience. He can be reached at [email protected].