Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

My original deque implementation and efficiency question original deque implementation and efficiency question lacked move semantics. After ratchet freak ratchet freak provided an example of how to define them I decided to try adding them to my deque. The unit test + output below shows that the code is working.

The following is the parts of the unit test added to the original source original source plus some context:

My original deque implementation and efficiency question lacked move semantics. After ratchet freak provided an example of how to define them I decided to try adding them to my deque. The unit test + output below shows that the code is working.

The following is the parts of the unit test added to the original source plus some context:

My original deque implementation and efficiency question lacked move semantics. After ratchet freak provided an example of how to define them I decided to try adding them to my deque. The unit test + output below shows that the code is working.

The following is the parts of the unit test added to the original source plus some context:

improved formatting (between test case source and output, corrected a copy/paste error)
Source Link
TOM__
  • 105
  • 7
BEGIN eDeque COPY TESTS
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
B.Size() < original.Size()
B_before_copyAssign size == 0
B = original
B result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
C.Size() > original.Size()
C_before_copyAssign size == 8
node 0 == 16
node 1 == 14
node 2 == 12
node 3 == 10
node 4 == 11
node 5 == 13
node 6 == 15
node 7 == 17 
C = original
C result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
original deque intact
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
incremented each node of C by 5
C result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
B.Size() == C.Size()
B = C
B result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
eDeque<int> G = eDeque<int>(B) move construction
G result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
incremented each node of B by 10
B result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
G = eDeque<int>(B) move assignment (B becomes unspecified)
G result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
B result size == 0
G.PushBack(std::move(lValue == 666)); G.PushFront(777) emplace and move
G result size == 7
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
END eDeque COPY TESTS
BEGIN eNODE COPY TESTS
eNode<int> H = eNode<int>(123) move construction result: H.Data() == 123
H = eNode<int>(456) move assignment result: H.Data() == 456, H.Next() == 0000000
0, H.Prev() == 00000000
G.PushFront(std::move(H.Data()))
G result size == 8
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
node 7 == 456
END eNODE COPY TESTS
BEGIN eDeque COPY TESTS
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
B.Size() < original.Size()
B_before_copyAssign size == 0
B = original
B result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
C = original
C result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
original deque intact
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
incremented each node of C by 5
C result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
B.Size() == C.Size()
B = C
B result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
eDeque<int> G = eDeque<int>(B) move construction
G result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
incremented each node of B by 10
B result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
G = eDeque<int>(B) move assignment (B becomes unspecified)
G result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
B result size == 0
G.PushBack(std::move(lValue == 666)); G.PushFront(777) emplace and move
G result size == 7
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
END eDeque COPY TESTS
BEGIN eNODE COPY TESTS
eNode<int> H = eNode<int>(123) move construction result: H.Data() == 123
H = eNode<int>(456) move assignment result: H.Data() == 456, H.Next() == 0000000
0, H.Prev() == 00000000
G.PushFront(std::move(H.Data()))
G result size == 8
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
node 7 == 456
END eNODE COPY TESTS
BEGIN eDeque COPY TESTS
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
B.Size() < original.Size()
B_before_copyAssign size == 0
B = original
B result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
C.Size() > original.Size()
C_before_copyAssign size == 8
node 0 == 16
node 1 == 14
node 2 == 12
node 3 == 10
node 4 == 11
node 5 == 13
node 6 == 15
node 7 == 17 
C = original
C result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
original deque intact
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
incremented each node of C by 5
C result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
B.Size() == C.Size()
B = C
B result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
eDeque<int> G = eDeque<int>(B) move construction
G result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
incremented each node of B by 10
B result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
G = eDeque<int>(B) move assignment (B becomes unspecified)
G result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
B result size == 0
G.PushBack(std::move(lValue == 666)); G.PushFront(777) emplace and move
G result size == 7
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
END eDeque COPY TESTS
BEGIN eNODE COPY TESTS
eNode<int> H = eNode<int>(123) move construction result: H.Data() == 123
H = eNode<int>(456) move assignment result: H.Data() == 456, H.Next() == 0000000
0, H.Prev() == 00000000
G.PushFront(std::move(H.Data()))
G result size == 8
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
node 7 == 456
END eNODE COPY TESTS
Source Link
TOM__
  • 105
  • 7

Templated double ended queue (deque) move semantics edge cases C++

My original deque implementation and efficiency question lacked move semantics. After ratchet freak provided an example of how to define them I decided to try adding them to my deque. The unit test + output below shows that the code is working.

However, my new question is: Are there edge cases in any of my move semantic functions that I may have forgotten, and is the data.~type(); necessary in the eNode<type>::operator=(type && other)? I'd also appreciate any feedback on my coding style.

template<class type>
class eDeque;
//*************************************************
// eNode
// to be used with friend class eDeque<type>
//*************************************************
template<class type>
class eNode {
 
 friend class eDeque<type>;
public :
// ... remainder of class definition (see referenced question)
 explicit eNode(type && data) : prev(nullptr), next(nullptr) { std::swap(this->data, data); }; // move constructor
 // DEBUG: destructor omitted because no heap allocation occurs
 eNode<type> & operator=(eNode<type> && other) { // move assignment
 data.~type(); 
 std::swap(this->data, other.data); 
 return *this;};
// ... remainder of class definition (see referenced question)
private:
 eNode<type> * prev;
 eNode<type> * next;
 type data;
};
template <class type>
class eDeque {
public:
// ... remainder of class definition (see referenced question)
 eDeque(eDeque<type> && other); // move constructor
 eDeque<type> & operator=(eDeque<type> && other); // move assignment
 void PushFront(type && data); // emplace and move
 void PushBack(type && data); // emplace and move
private:
 eNode<type> * front;
 eNode<type> * back;
 int nodeCount;
 // ... remainder of class definition (see referenced question)
};
//******************
// eDeque::eDeque
// move constructor
//******************
template <class type>
inline eDeque<type>::eDeque(eDeque<type> && other) : nodeCount(0), front(nullptr), back(nullptr) {
 std::swap(nodeCount, other.nodeCount);
 std::swap(front, other.front);
 std::swap(back, other.back);
}
//******************
// eDeque::operator=
// move assignment
//******************
template <class type>
inline eDeque<type> & eDeque<type>::operator=(eDeque<type> && other) {
 Clear();
 std::swap(nodeCount, other.nodeCount);
 std::swap(front, other.front);
 std::swap(back, other.back);
 return *this;
}
//******************
// eDeque::PushFront
// emplace and move
//******************
template <class type>
inline void eDeque<type>::PushFront(type && data) {
 eNode<type> * newFront;
 newFront = new eNode<type>(std::move(data));
 if (front == nullptr) {
 back = newFront;
 front = newFront;
 } else {
 newFront->prev = front;
 front->next = newFront;
 front = newFront;
 }
 nodeCount++;
}
//******************
// eDeque::PushBack
// emplace and move
//******************
template <class type>
inline void eDeque<type>::PushBack(type && data) {
 eNode<type> * newBack;
 newBack = new eNode<type>(std::move(data));
 if (back == nullptr) {
 back = newBack;
 front = newBack;
 }
 else {
 newBack->next = back;
 back->prev = newBack;
 back = newBack;
 }
 nodeCount++;
}

The following is the parts of the unit test added to the original source plus some context:

#include "Deque.h"
// iterate and print back to front
template<class type>
void PrintDeque(const eDeque<type> & de, const char * name) {
 eNode<int> * iterator;
 int i;
 printf("%s size == %i\n", name, de.Size());
 for (i = 0, iterator = de.Back(); iterator != nullptr; iterator = iterator->Next())
 printf("node %i == %i\n", i++, iterator->Data());
 printf("\n\n");
}
// iterate and increment by amount back to front
template<class type>
void IncrementData(const eDeque<type> & de, int amount) {
 eNode<int> * iterator;
 for (iterator = de.Back(); iterator != nullptr; iterator = iterator->Next())
 iterator->Data() += amount;
}
// unit test
int main() {
 int lValues[] = { 0, 1, 2, 3, 4, 5, 6 };
 printf("BEGIN eDeque COPY TESTS\n\n");
 eDeque<int> original;
 original.PushFront(lValues[0]);
 original.PushFront(lValues[1]);
 original.PushFront(lValues[2]);
 original.PushFront(lValues[3]);
 original.PushFront(lValues[4]);
 original.PushFront(lValues[5]);
 original.PushBack(lValues[6]);
 original.PopBack();
 original.PopFront();
 PrintDeque(original, "original");
 eDeque<int> B;
 printf("B.Size() < original.Size()\n");
 PrintDeque(B, "B_before_copyAssign");
 B = original; // copy assignment test with B.Size() < original.Size()
 printf("B = original\n");
 PrintDeque(B, "B result");
 eDeque<int> C;
 // these are now emplace and move calls
 C.PushBack(10);
 C.PushFront(11);
 C.PushBack(12);
 C.PushFront(13);
 C.PushBack(14);
 C.PushFront(15);
 C.PushBack(16);
 C.PushFront(17);
 printf("C.Size() > original.Size()\n");
 PrintDeque(C, "C_before_copyAssign");
 C = original; // copy assignment test with C.Size() > original.Size()
 printf("C = original\n");
 PrintDeque(C, "C result");
 // verify the original is intact
 printf("original deque intact\n");
 PrintDeque(original, "original");
 IncrementData(C, 5);
 printf("incremented each node of C by 5\n");
 PrintDeque(C, "C result");
 
 printf("B.Size() == C.Size()\n");
 B = C; // copy assignment test with B.Size() == C.Size()
 printf("B = C\n");
 PrintDeque(B, "B result");
// BEGIN eDeque move semantics testing
 eDeque<int> G = eDeque<int>(B); // copy construct an rvalue eDeque, then move construct G
 printf("eDeque<int> G = eDeque<int>(B) move construction\n");
 PrintDeque(G, "G result");
 
 IncrementData(B, 10);
 printf("incremented each node of B by 10\n");
 PrintDeque(B, "B result");
 
 G = eDeque<int>(std::move(B)); // move construct an rvalue eDeque, then move assign G (B becomes undefined/unspecified)
 printf("G = eDeque<int>(B) move assignment (B becomes unspecified)\n");
 PrintDeque(G, "G result");
 PrintDeque(B, "B result");
 int lValue = 666;
 printf("G.PushBack(std::move(lValue == 666)); G.PushFront(777) emplace and move\n");
 G.PushBack(std::move(lValue)); // emplace and move
 G.PushFront(777); // emplace and move
 PrintDeque(G, "G result");
// END eDeque move semantics testing
 printf("END eDeque COPY TESTS\n\n");
 printf("BEGIN eNODE COPY TESTS\n\n");
// BEGIN eNode move semantics testing
 eNode<int> H = eNode<int>(123); // move construction
 printf("eNode<int> H = eNode<int>(123) move construction result: H.Data() == %i\n\n", H.Data());
 H = eNode<int>(456); // move assignment
 printf("H = eNode<int>(456) move assignment result: H.Data() == %i, H.Next() == %p, H.Prev() == %p\n\n", H.Data(), H.Next(), H.Prev());
 printf("G.PushFront(std::move(H.Data()))\n");
 G.PushFront(std::move(H.Data())); // H.data now unspecified
 PrintDeque(G, "G result");
// END eNode move semantics testing
 printf("END eNODE COPY TESTS\n\n");
 return 0;
}

The following is the output of the relevant unit test code:

BEGIN eDeque COPY TESTS
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
B.Size() < original.Size()
B_before_copyAssign size == 0
B = original
B result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
C = original
C result size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
original deque intact
original size == 5
node 0 == 0
node 1 == 1
node 2 == 2
node 3 == 3
node 4 == 4
incremented each node of C by 5
C result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
B.Size() == C.Size()
B = C
B result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
eDeque<int> G = eDeque<int>(B) move construction
G result size == 5
node 0 == 5
node 1 == 6
node 2 == 7
node 3 == 8
node 4 == 9
incremented each node of B by 10
B result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
G = eDeque<int>(B) move assignment (B becomes unspecified)
G result size == 5
node 0 == 15
node 1 == 16
node 2 == 17
node 3 == 18
node 4 == 19
B result size == 0
G.PushBack(std::move(lValue == 666)); G.PushFront(777) emplace and move
G result size == 7
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
END eDeque COPY TESTS
BEGIN eNODE COPY TESTS
eNode<int> H = eNode<int>(123) move construction result: H.Data() == 123
H = eNode<int>(456) move assignment result: H.Data() == 456, H.Next() == 0000000
0, H.Prev() == 00000000
G.PushFront(std::move(H.Data()))
G result size == 8
node 0 == 666
node 1 == 15
node 2 == 16
node 3 == 17
node 4 == 18
node 5 == 19
node 6 == 777
node 7 == 456
END eNODE COPY TESTS
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /