0

I was wondering if that type of thing falls under compiler's optimizations purview. From what I've gathered from this talk even std::unique_ptr is not truly "zero-cost" in part due to the implicit indirection of this pointer which plays a role in passing the actual underlying pointer to the unique pointer's member function.

Is there always a reference involved in passing member fields to methods of a class or can the compiler see that, say this method does not use certain fields and doesn't modify the rest so it will just pass them by value?

Big Temp
  • 434
  • 4
  • 12
  • Passing by reference and passing by value is determined by the function declaration. –  Mar 22 '20 at 00:33
  • 1
    @Chipster I mean the implicit passing of the underlying data fields of a class, not regular parameters. I'll edit this question, it does sound like I have normal parameters in mind. – Big Temp Mar 22 '20 at 00:40
  • Member fields are never passed directly to a method of a class, just the `this` pointer. Optimization with inline function can eliminate this overhead completely. – 1201ProgramAlarm Mar 22 '20 at 00:51
  • Would the following be a fair rephrasing of your question? *Can the compiler see that a more efficient approach would produce the same results [as-if](https://stackoverflow.com/questions/15718262/what-exactly-is-the-as-if-rule) no optimizations were performed, and choose to optimize?* – JaMiT Mar 22 '20 at 01:03
  • @JaMiT Yes, I suppose. And now that I think about it, it does become a very trivial question when phrased that way. It's just after that talk I started to wonder how often the compiler can see the better approach – Big Temp Mar 22 '20 at 01:44
  • 1
    If the compiler can see the definition of the class and its member functions, then it can practically often eliminate most, if not all, overhead associated with passing `this` and indirection to access members. With templates, the compiler often has that sort of visibility, so can optimise until it is content. Some smarter linkers are also capable of such optimisations between compilation units. – Peter Mar 22 '20 at 02:30
  • Could you provide timestamps from the talk where "the implicit indirection of `this` pointer" is mentioned in connection to `unique_ptr`? I thought I found the segment focusing on `unique_ptr`, but that part talked about the overhead associated with transferring ownership and did not mention the `this` pointer (presumably because all the member functions had been inlined). – JaMiT Mar 22 '20 at 22:38
  • @JaMiT 57:00 is when he talks about it – Big Temp Mar 22 '20 at 22:42
  • @BigTemp That Q&A is not about passing `this` to a member function. (In fact, mentioning "`this`" was probably a mistake made while trying to figure out what the question was.) The pointer being discussed there is an artifact of the ABI when calling a *non-member* function. – JaMiT Mar 22 '20 at 22:56

1 Answers1

1

There seems to be some misunderstanding of what the talk discusses. There is a discussion of why unique_ptr is not "zero-cost". However, that discussion focuses on a specific case, the transferal of ownership. On the one hand, since there is a situation where there are costs, it is true that unique_ptr is not zero-cost. On the other hand, that conclusion is misleading, as it sounds just as all-encompassing as saying that it is zero-cost. A more accurate description would combine the two views: unique_ptr can be a zero-cost replacement for a raw pointer, but not always.

A unique_ptr can be zero-cost. The first question from the Q&A session at the end of the talk addresses this (starting at 36:36). Most member functions of smart_ptr are simple enough to be inlined by any C++ compiler that understands template syntax. There is no overhead associated with the this pointer and member functions. If you never transfer ownership, go on thinking of unique_ptr as zero-cost.

The extra cost comes when ownership is transferred. The talk specifically focused on passing a unique_ptr as a parameter to a function. This unambiguously gives the called function ownership of whatever the pointer points to. It also entails an additional run-time cost (two additional costs if the raw pointer version lacked exception safety).

The extra cost is not intrinsic to the C++ language, but rather comes from a commonly-used ABI (application binary interface). The ABI defines at a low level (think assembly) how parameters are passed to functions. According to this convention, there is an important difference between T* and unique_ptr<T> – the former is a primitive type, while the latter is an instance of a class. If I understood this part of the talk correctly, the ABI calls for primitive types to be placed directly in the call stack (potentially simply stored in a register), whereas class instances must exist in main memory and a pointer to the instance is placed directly in the stack / potentially in a register. Yes, even if the object is passed by value. Why? Because that's what the convention calls for. (There are better reasons, but they are tangential to the current subject.) In order for things like dynamic libraries to work, there needs to be a convention, and this ABI is what we have.

The upshot is that primitives receive preferential treatment, making them faster. When you switch a function's parameter from a pointer to a class instance, there is a runtime cost (of unknown size – it might be insignificant). This is the cost that prevents unique_ptr from being zero-cost in all cases. Zero-cost in many common cases, but not when a function takes a unique_ptr argument.

JaMiT
  • 14,422
  • 4
  • 15
  • 31