Writing Merge Sort in C++ I am learning programming online and currently watching CS50 lectures, in third lecture, professor introduces us to merge_sort though only through pseudo code, so I wanted someone to review my implementation and tell me where I can improve and what I possibly missed.

#include &lt;algorithm&gt;
#include &lt;assert.h&gt;
#include &lt;cmath&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;

template &lt;typename T&gt; void merge_sort(T m_array[], const size_t size) {
    using namespace std;
    if (size &lt; 2)
        return;
    else if (size == 2) {
        if (m_array[0] &gt; m_array[1])
            std::swap(m_array[0], m_array[1]); // no need for a new array
        return;
    }
    merge_sort(m_array, size / 2);
    merge_sort(m_array + size / 2,
               std::ceil(static_cast&lt;double&gt;(size) /
                         2) // for odd size, divison will have truncated value
                            // and recursion will left the the last array value
                            // for sorting, size%2==0?size/2:size/2+1
    );

    T *new_array = new T[size];
    size_t na_pos = 0;

    const T *array1 = m_array, *array2 = m_array + size / 2;

    const T *const array1end = m_array + size / 2, *const array2end =
                                                       m_array + size;

    while (1) {
        if (array1 == array1end)
            break;
        if (array2 == array2end)
            break;

        if (*array1 &lt; *array2)
            new_array[na_pos++] = *array1++;
        else if (*array2 &lt; *array1)
            new_array[na_pos++] = *array2++;
        else if (*array1 == *array2) {
            new_array[na_pos++] = *array1++;
            new_array[na_pos++] = *array2++;
        }
    }

    assert(array1 == array1end || array2 == array2end);

    while (array1 != array1end)
        new_array[na_pos++] = *array1++;
    while (array2 != array2end)
        new_array[na_pos++] = *array2++;
    assert(na_pos == size);

    for (na_pos = 0; na_pos &lt; size; na_pos++)
        m_array[na_pos] = new_array[na_pos];

    delete[] new_array;
}

int main() {
    using namespace std;

    auto limit = 10000;
    const auto size = 21;
    while (limit--) {
        vector&lt;int&gt; a;
        a.reserve(size);
        while (a.size() &lt; size)
            a.push_back(rand() % 10000);
        merge_sort(a.data(), a.size());
        assert(std::is_sorted(a.begin(), a.end()));
    }

    return 0;
}
std::ceil(static_cast&lt;double&gt;(size) / 2 is a very long (and unclear) way to say size - size/2.
No naked loops please. Each loop represents an important algorithm, and deserves a name. For example,

while (array1 != array1end)
    new_array[na_pos++] = *array1++;


wants to be copy(new_array + na_pos, array1, array1_end);, and you may reuse it at least 2 more times (and don't make it void: it has something interesting to return).

Similarly, the merging loop represents a merge algorithm.
The block

if (*array1 &lt; *array2)
    new_array[na_pos++] = *array1++;
else if (*array2 &lt; *array1)
    new_array[na_pos++] = *array2++;
else if (*array1 == *array2) {
    new_array[na_pos++] = *array1++;
    new_array[na_pos++] = *array2++;
}


introduces a subtle problem. Here your algorithm may lose stability. If array1 has two elements comparing equal, say x1,x2, and array2 has an element x3 which also compares equal to them, the final arrangement will be x1, x3, x2, whereas the stable sort should result in x1, x2, x3.

The problem is easy to fix:

if (*array1 &lt;= *array2) {
    new_array[na_pos++] = *array1++;
} else {
    new_array[na_pos++] = *array2++;
}

I strongly recommend to put the loop termination conditions where they belong:

while ((array1 != array1end) &amp;&amp; (array2 != array2end))