Adding two singly linked lists in C++
Eliminate size

The size function is not useful. Imagine if one list contains 1 element and the other contains a million. If you're lucky you might traverse the shorter list first, and use that size to stop traversing the second list early when possible.

Instead of trying to check the size first, you could adjust the main loop in add from this:


while (l1 != NULL) {



to this:

while (l1 != NULL &amp;&amp; l2 != NULL) {


and add this condition after, to prepare for the second loop:

if (l1 != NULL) {
    l2 = l1;
}


More natural int carry

Instead of bool carry_over, it would be more natural to have an int carry, with 0 or 1 as values. The end result is the same, but more natural, less surprising.

Duplicated adding logic

The logic of adding is duplicated several times:


For the first pair of elements
For the pairs of elements while exist
For the remaining elements of the longer list


You can easily eliminate the first, by using a dummy node to mark the head of the new list. The value of this node will not be used, but dummy-&gt;next will point to the first element. In addition, this little trick will make the implementation more robust, and handle the case when one of the lists is empty (null).

Declare variables in the smallest scope

There's no need to declare x at the top. You can declare it inside the loops where needed.

Naming

Lowercase l is one of the worst possible names for a variable. In some fonts it might look like the number one. Almost any name would be better than that. For example node.

Braces

It's recommended to use braces always, even with single-statement if.

Suggested implementation

Applying the above suggestions, the implementation becomes:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        return add(l1, l2);
    }

private:

    /**
     * Input: Two lists l1 and l2 with size(l1) &lt;= size(l2)
     * Output: result list
     */
    ListNode* add(const ListNode *l1, const ListNode *l2) {
        // dummy node, helps simplify the code a bit
        ListNode dummy(0);
        ListNode *node = &amp;dummy;

        int carry = 0;

        while (l1 != NULL &amp;&amp; l2 != NULL) {
            int x = l1-&gt;val + l2-&gt;val + carry;
            if (x &gt; 9) {
                carry = 1;
                x -= 10;
            } else {
                carry = 0;
            }
            node = node-&gt;next = new ListNode(x);
            l1 = l1-&gt;next;
            l2 = l2-&gt;next;
        }

        if (l1 != NULL) {
            l2 = l1;
        }

        while (l2 != NULL) {
            int x = l2-&gt;val + carry;
            if (x &gt; 9) {
                carry = 1;
                x -= 10;
            } else {
                carry = 0;
            }
            node = node-&gt;next = new ListNode(x);
            l2 = l2-&gt;next;
        }

        if (carry) {
            node-&gt;next = new ListNode(1);
        }

        return dummy.next;
    }
};


Speed

I suppose the exercise comes from here.
I don't know how to make this faster.
I submitted your original code, and some variations, but the result appears to be randomly within 36-56ms. At 36ms it beats 64% of submissions, at 40ms it beats only 18% of submissions. But I don't think speed is important at all. The time complexity of your algorithm is \$O(n)\$, and I don't think it's possible to solve this problem faster than that. Any speed optimizations at this level are just micro-optimizations, neither relevant nor interesting.