‹ BackHN Continuity

Thread

Writing Efficient C++ Code (2013)

176 points · 161 comments · ibobev

  1. asveikau · · focus · HN ↗
    This article reminds me of performance advice I was starting to see in the 2000s decade. Basically it was to not introduce a bunch of pointer heavy data structures to get lower algorithmic complexity. Stuff it all into a vector. You will use some algorithms that the computer science textbook will say it's slower, but if it fits all in cache it doesn't matter. The cache misses following pointers all over town hurts you more.
    1. tialaramex · · focus · HN ↗
      This is partly because the C++ stdlib looks like they've given you all the basic tools you need - unlike the C standard library - yet in fact many of these tools are hopelessly obsolete. It's not quite PHP's "fractal of bad design", these are all reasonable tools... if it's 1985. The linked lists make sense on hardware where five pointer fetches and five consecutive memory reads cost roughly the same - 1985 hardware.

      The growable array type std::vector<T> is least impacted by these archaic choices out of the tools in the box you're likely to reach for. So it will make sense very often to choose this type first.

      1. adrianN · · focus · HN ↗
        Linked lists are great data structures for the use cases where you need their properties. It’s just that you don’t encounter those scenarios very often in most kinds of software.
        1. someonebaggy · · focus · HN ↗
          You say not very often, but the true usefulness is almost never. Extremely little. One in a trillion times. Even when you think linked lists would be faster, they usually aren't.
          1. ernst_klim · · focus · HN ↗
            It's pretty useful, just not as a "sequential container" as people are usually taught. And definitely now with an interface C++ provides. There are two main cases for linked lists:

              1. When you need a persistent version of sequential data structure. I.e. you need addition not to change the previous version of list. Very useful in traversals which can fail and/or have multiple routes. C++ list obviously fails here because it's a mutable data structure and each addition is mutation. The proper interface is cons(head, old_list) -> new_list, where old_list exists after new_list is constructed.
            
              2. When you need the values be never moved in memory. Aka intrusive lists. Can be optimized for more cache friendliness by having lists of big chunks of values instead of just lists in some cases. Useful in operating systems and many low level apps. Alternative is usually a vector of pointers which still gives you indirection.
            1. MaxBarraclough · · focus · HN ↗
              I'm not sure I follow the second point. Array-based solutions are able to guarantee that an element is never relocated, it's just that std::vector doesn't offer this guarantee. The Boost libraries offer this though, they call it stable_vector.

              <a href="https:&#x2F;&#x2F;www.boost.org&#x2F;doc&#x2F;libs&#x2F;1_92_0&#x2F;doc&#x2F;html&#x2F;container&#x2F;non_standard_containers.html#container.non_standard_containers.stable_vector" rel="nofollow">https:&#x2F;&#x2F;www.boost.org&#x2F;doc&#x2F;libs&#x2F;1_92_0&#x2F;doc&#x2F;html&#x2F;container&#x2F;non...

              1. ernst_klim · · focus · HN ↗
                &gt; Array-based solutions are able to guarantee that an element is never relocated

                This is an array of pointers, I mentioned it in the post you&#x27;re replying to. It completely obliterates the &quot;cache-friendliness&quot; argument, making it worse than linked list (now you have same indirection overhead plus overhead of copying minus benefits of being able to CAS your value atomically into a list making it lock-free)

                1. MaxBarraclough · · focus · HN ↗
                  Yes you&#x27;re right. Here&#x27;s an alternative that behaves the way I had in mind but doesn&#x27;t support deletions, as handling deletions the way std::vector does would naturally mean relocating elements. [0]

                  I figure it would be possible to add support for deletions, but it would cost us: we would lose guaranteed contiguous placement of elements with neighbouring indices, and (unless no deletions are made) we&#x27;d need a private data structure to correspond vector indices to addresses, and to determine where to locate new elements. This would of course bring us back to continually paying the price of indirection overhead, and simple lock-free modifications would not be possible.

                  My completely unsupported guess is the cache behaviour wouldn&#x27;t be too bad unless deletions (of elements that aren&#x27;t at the end of the vector) are common. I imagine the cache behaviour of a linked list must depend greatly on what the allocator gives you. Presumably using a pool, specific to that particular list, could help there.

                  [0] <a href="https:&#x2F;&#x2F;github.com&#x2F;david-grs&#x2F;stable_vector" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;david-grs&#x2F;stable_vector

                2. someonebaggy · · focus · HN ↗
                  Arrays of pointers are more cache-friendly than linked lists because the pointers can all be traversed in parallel.
Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.