diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index b812f8ff43cb7b95e52f73af02aa6f7add35e3fa..9069bb10c2be67d2d865c017be0100be68494640 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -97,7 +97,7 @@ class DicNode {
 
     DicNode(const DicNode &dicNode);
     DicNode &operator=(const DicNode &dicNode);
-    virtual ~DicNode() {}
+    ~DicNode() {}
 
     // Init for copy
     void initByCopy(const DicNode *const dicNode) {
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h
index c41a7243a64687358907c893fbe53d0f8cd012b4..ab02e6192e53dff9b9a6260170c0bfaf91a5274e 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h
@@ -33,7 +33,7 @@ class DicNodeProperties {
               mIsTerminal(false), mHasChildrenPtNodes(false), mIsBlacklistedOrNotAWord(false),
               mDepth(0), mLeavingDepth(0) {}
 
-    virtual ~DicNodeProperties() {}
+    ~DicNodeProperties() {}
 
     // Should be called only once per DicNode is initialized.
     void init(const int pos, const int childrenPos, const int nodeCodePoint, const int probability,
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h
index b0fddb72431ba35eb7d1284cddcbb3e7a20b0be3..f79ac7b2cf5cab271aef23362b56b11281aff6bd 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h
@@ -37,7 +37,18 @@ class DicNodeState {
               mDicNodeStateScoring() {
     }
 
-    virtual ~DicNodeState() {}
+    ~DicNodeState() {}
+
+    DicNodeState &operator=(const DicNodeState& src) {
+        init(&src);
+        return *this;
+    }
+
+    DicNodeState(const DicNodeState& src)
+            : mDicNodeStateInput(), mDicNodeStateOutput(), mDicNodeStatePrevWord(),
+              mDicNodeStateScoring() {
+        init(&src);
+    }
 
     // Init with prevWordPos
     void init(const int prevWordPos) {
@@ -62,11 +73,6 @@ class DicNodeState {
         mDicNodeStateOutput.addMergedNodeCodePoints(
                 mergedNodeCodePointCount, mergedNodeCodePoints);
     }
-
- private:
-    // Caution!!!
-    // Use a default copy constructor and an assign operator because shallow copies are ok
-    // for this class
 };
 } // namespace latinime
 #endif // LATINIME_DIC_NODE_STATE_H
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h
index bbd9435b59d15184ad6c8169101b571af46a4440..3d788114fa48510f6a8fa6bb1fe475647f44ba86 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h
@@ -25,7 +25,7 @@ namespace latinime {
 class DicNodeStateInput {
  public:
     DicNodeStateInput() {}
-    virtual ~DicNodeStateInput() {}
+    ~DicNodeStateInput() {}
 
     // TODO: Merge into DicNodeStatePrevWord::truncate
     void truncate(const int commitPoint) {
@@ -89,9 +89,8 @@ class DicNodeStateInput {
     }
 
  private:
-    // Caution!!!
-    // Use a default copy constructor and an assign operator because shallow copies are ok
-    // for this class
+    DISALLOW_COPY_AND_ASSIGN(DicNodeStateInput);
+
     int mInputIndex[MAX_POINTER_COUNT_G];
     int mPrevCodePoint[MAX_POINTER_COUNT_G];
     float mTerminalDiffCost[MAX_POINTER_COUNT_G];
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h
index abafc0edffd98f1adf2b6cbb6c1c29ce2e86a73a..011d020c40343248edafaca5f8ca8b5de5c5058e 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h
@@ -27,11 +27,9 @@ namespace latinime {
 
 class DicNodeStateOutput {
  public:
-    DicNodeStateOutput() : mOutputtedCodePointCount(0) {
-        init();
-    }
+    DicNodeStateOutput() : mOutputtedCodePointCount(0) {}
 
-    virtual ~DicNodeStateOutput() {}
+    ~DicNodeStateOutput() {}
 
     void init() {
         mOutputtedCodePointCount = 0;
@@ -72,9 +70,8 @@ class DicNodeStateOutput {
     int mCodePointsBuf[MAX_WORD_LENGTH];
 
  private:
-    // Caution!!!
-    // Use a default copy constructor and an assign operator because shallow copies are ok
-    // for this class
+    DISALLOW_COPY_AND_ASSIGN(DicNodeStateOutput);
+
     uint16_t mOutputtedCodePointCount;
 };
 } // namespace latinime
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
index 7868f785379cf0683aee88a7fc0cf54677f00f5e..a35eb5124db435ee044cf702f1f6f571f1b38252 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
@@ -31,20 +31,9 @@ class DicNodeStatePrevWord {
  public:
     AK_FORCE_INLINE DicNodeStatePrevWord()
             : mPrevWordCount(0), mPrevWordLength(0), mPrevWordStart(0), mPrevWordProbability(0),
-              mPrevWordPtNodePos(NOT_A_DICT_POS), mSecondWordFirstInputIndex(NOT_AN_INDEX) {
-        memset(mPrevWord, 0, sizeof(mPrevWord));
-    }
+              mPrevWordPtNodePos(NOT_A_DICT_POS), mSecondWordFirstInputIndex(NOT_AN_INDEX) {}
 
-    virtual ~DicNodeStatePrevWord() {}
-
-    void init() {
-        mPrevWordLength = 0;
-        mPrevWordCount = 0;
-        mPrevWordStart = 0;
-        mPrevWordProbability = -1;
-        mPrevWordPtNodePos = NOT_A_DICT_POS;
-        mSecondWordFirstInputIndex = NOT_AN_INDEX;
-    }
+    ~DicNodeStatePrevWord() {}
 
     void init(const int prevWordNodePos) {
         mPrevWordLength = 0;
@@ -53,6 +42,7 @@ class DicNodeStatePrevWord {
         mPrevWordProbability = -1;
         mPrevWordPtNodePos = prevWordNodePos;
         mSecondWordFirstInputIndex = NOT_AN_INDEX;
+        mPrevWord[0] = 0;
     }
 
     // Init by copy
@@ -141,9 +131,8 @@ class DicNodeStatePrevWord {
     int mPrevWord[MAX_WORD_LENGTH];
 
  private:
-    // Caution!!!
-    // Use a default copy constructor and an assign operator because shallow copies are ok
-    // for this class
+    DISALLOW_COPY_AND_ASSIGN(DicNodeStatePrevWord);
+
     int16_t mPrevWordCount;
     int16_t mPrevWordLength;
     int16_t mPrevWordStart;
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
index 18b7d736a224a013ab31adcfb8c347d5736baa39..458eac81b1bc52d8de90a7aed4dd21a23e23a1f5 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
@@ -37,7 +37,7 @@ class DicNodeStateScoring {
               mNormalizedCompoundDistanceAfterFirstWord(MAX_VALUE_FOR_WEIGHTING) {
     }
 
-    virtual ~DicNodeStateScoring() {}
+    ~DicNodeStateScoring() {}
 
     void init() {
         mEditCorrectionCount = 0;
@@ -175,9 +175,8 @@ class DicNodeStateScoring {
     }
 
  private:
-    // Caution!!!
-    // Use a default copy constructor and an assign operator because shallow copies are ok
-    // for this class
+    DISALLOW_COPY_AND_ASSIGN(DicNodeStateScoring);
+
     DoubleLetterLevel mDoubleLetterLevel;
     DigraphUtils::DigraphCodePointIndex mDigraphIndex;
 
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index c3b670337d009013286759da85003c09929082f9..f60a210d4261c34f6944201e95631afdaa2a7d4a 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -248,17 +248,16 @@ void Suggest::processTerminalDicNode(
     if (dicNode->shouldBeFilteredBySafetyNetForBigram()) {
         return;
     }
+    if (!dicNode->hasMatchedOrProximityCodePoints()) {
+        return;
+    }
     // Create a non-cached node here.
-    DicNode terminalDicNode;
-    DicNodeUtils::initByCopy(dicNode, &terminalDicNode);
+    DicNode terminalDicNode(*dicNode);
     if (TRAVERSAL->needsToTraverseAllUserInput()
             && dicNode->getInputIndex(0) < traverseSession->getInputSize()) {
         Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_TERMINAL_INSERTION, traverseSession, 0,
                 &terminalDicNode, traverseSession->getMultiBigramMap());
     }
-    if (!dicNode->hasMatchedOrProximityCodePoints()) {
-        return;
-    }
     Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_TERMINAL, traverseSession, 0,
             &terminalDicNode, traverseSession->getMultiBigramMap());
     traverseSession->getDicTraverseCache()->copyPushTerminal(&terminalDicNode);
@@ -375,6 +374,7 @@ void Suggest::processDicNodeAsTransposition(DicTraverseSession *traverseSession,
         DicNode *dicNode) const {
     const int16_t pointIndex = dicNode->getInputIndex(0);
     DicNodeVector childDicNodes1;
+    DicNodeVector childDicNodes2;
     DicNodeUtils::getAllChildDicNodes(dicNode, traverseSession->getDictionaryStructurePolicy(),
             &childDicNodes1);
     const int childSize1 = childDicNodes1.getSizeAndLock();
@@ -386,7 +386,7 @@ void Suggest::processDicNodeAsTransposition(DicTraverseSession *traverseSession,
             continue;
         }
         if (childDicNodes1[i]->hasChildren()) {
-            DicNodeVector childDicNodes2;
+            childDicNodes2.clear();
             DicNodeUtils::getAllChildDicNodes(childDicNodes1[i],
                     traverseSession->getDictionaryStructurePolicy(), &childDicNodes2);
             const int childSize2 = childDicNodes2.getSizeAndLock();