Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <memory>
- #include <string>
- struct ContainerTester {
- static int instances;
- int counter{};
- int val;
- ContainerTester() : ContainerTester(-1) {};
- ContainerTester(int val) : val(val)
- {
- ++counter;
- ++instances;
- //~ std::cout << "create " << val << std::endl;
- }
- ContainerTester(ContainerTester const& rhs) : counter(rhs.counter), val(rhs.val)
- {
- //~ std::cout << "copy " << val << std::endl;
- ++instances;
- }
- ~ContainerTester() {
- //~ std::cout << "destroy " << val << std::endl;
- --counter;
- --instances;
- if (counter < 0) std::cout << "multiple destructor calls on same element" << std::endl;
- if (instances < 0) std::cout <<"negative number of instances" << std::endl;
- }
- };
- int ContainerTester::instances{};
- std::ostream& operator<<(std::ostream& o, const ContainerTester& c) {return o << c.val;}
- template<typename T> class Deque {
- public:
- Deque():
- current_capacity(8)
- ,push_back_position(current_capacity/2)
- ,push_front_position(push_back_position - 1)
- {arr = malloc.allocate(current_capacity);}
- size_t size() const {
- return current_size;
- }
- void push_back(const T &item);
- void push_front(const T &item);
- T pop_front();
- T pop_back();
- //why returning by value? return by reference
- T const& front() const {
- //could hardly be expressed in a more complicated way :)
- // and the - 1 has to be a + 1 anyway
- //~ return *((arr + push_front_position) - 1);
- return arr[push_front_position + 1];
- }
- //why returning by value return by reference
- T const& back() const {
- //could hardly be expressed in a more complicated way :)
- //~ return *((arr + push_back_position) - 1);
- return arr[push_back_position - 1];
- }
- //btw you may want T& front() and T& back() too, to hand out modifiable references
- //as for now, the output operator has to access private Deque members
- friend std::ostream& operator<<(std::ostream&, Deque<auto> const&);
- private:
- T *arr = nullptr;
- void reallocate();
- size_t current_size = 0;
- size_t current_capacity;
- // current_capacity is uninitialized here (has an arbitrary value)
- // and you initialize push_*_position on behalf of this arbitrary value
- //~ size_t push_back_position = (current_capacity / 2) + 1;
- //~ size_t push_front_position = current_capacity / 2;
- size_t push_back_position;
- size_t push_front_position;
- static std::allocator<T> malloc;
- };
- template<typename T> std::allocator<T> Deque<T>::malloc;
- template<typename T> void Deque<T>::reallocate() {
- T *new_arr = malloc.allocate(current_capacity * 2);
- //the data has to be centered in new_arr, you put it at its beginning
- std::uninitialized_copy(arr, arr + current_capacity, new_arr + current_capacity - current_size/2 - 1);
- //allocator::destroy has been removed in C++20
- //~ for (size_t i = 0; i != current_capacity; ++i)
- //~ malloc.destroy(arr + i);
- //deallocate calls operator delete, which calls the destructor
- malloc.deallocate(arr, current_capacity);
- arr = new_arr;
- //~ current_capacity = current_capacity * 2;
- current_capacity *= 2;
- //you reset the insert positions to the center of new_arr
- //~ push_back_position = (current_capacity / 2) + 1;
- //~ push_front_position = current_capacity / 2;
- //they have to be set off by half of the number of elements
- push_back_position = current_capacity/2 + current_size/2;
- push_front_position = current_capacity/2 - current_size/2 - 1;
- }
- template<typename T> void Deque<T>::push_back(const T &item) {
- //if your Deque has a capacity of e.g. 8 and a size of 0, and you push_back 5 elements, then it has a size of 5, but push_back_position would be capacity + 1, which is obviously wrong
- //~ if (current_size + 1 > current_capacity)
- if (push_back_position > current_capacity)
- reallocate();
- // allocator::construct was removed in C++20
- //~ malloc.construct(arr + push_back_position, item);
- //this in fact calls the assignment operator
- //if you really want to call the copy constructor, you can use placement new
- arr[push_back_position] = item;
- ++push_back_position;
- ++current_size;
- //debug output
- std::cout << "PB: " << *this << " @" << push_back_position << std::endl;
- }
- template<typename T> void Deque<T>::push_front(const T &item) {
- // see ::push_back, similar problem
- //~ if (current_size + 1 > current_capacity)
- if (push_front_position == 0)
- reallocate();
- // allocator::construct was removed in C++20
- //~ malloc.construct(arr + push_front_position, item);
- //this in fact calls the assignment operator
- //if you really want to call the copy constructor, you can use placement new
- arr[push_front_position] = item;
- --push_front_position;
- ++current_size;
- //debug output
- std::cout << "PF: " << *this << " @" << push_front_position << std::endl;
- }
- //outputs the Deque, useful for debugging
- std::ostream& operator<<(std::ostream& o, Deque<auto> const& d)
- {
- for (auto i{d.push_front_position + 1}; i < d.push_back_position; ++i)
- o << d.arr[i] << " ";
- return o;
- }
- //the correct signature of main is int main(int, char**)
- //~ int main() {
- int main(int, char**) {
- Deque<ContainerTester> test;
- for (int i = 0; i < 5; ++i)
- test.push_front(i);
- for (int i = 5; i <= 10; ++i)
- test.push_back(i);
- //added by me
- for (int i = 11; i < 20; ++i)
- test.push_front(i);
- std::cout << test.front() << std::endl;
- std::cout << test.back() << std::endl;
- std::cout << test << std::endl;
- return 0; //obsolete: if main returns without an explicit return, it's implicitly return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement