Home > Blockchain >  Is there any realistic use case for passing pointers by constant reference rather than by value?
Is there any realistic use case for passing pointers by constant reference rather than by value?

Time:07-15

Since a reference (some-type&) behaves as a constant pointer (some-type * const), passing an argument via a "constant reference to pointer" parameter (some-type * const&) seems a bit redundant, because

  • if the parameter is some-type *
    • I'm copying it,
    • I can't edit the original because I just don't handle it;
  • if the parameter is some-type * const&
    • I'm not copying it,
    • I can't edit the orignal because I hold it as a const entity.

So in some way the only difference between the two is that the former incurs a copy, whereas the latter doesn't.

In turn, this means that this difference can be relatively important for std::shared_ptrs, which can be bigger than raw pointers and std::unique_ptrs.

But is that (passing std::shared_ptrs by const& if they are "heavy") the only usecase for passing pointer arguments by const&?


As regards the observation that the pointer aspect of the question is unnecessary, I think that when talking of non pointer-like data types, it's kind of easy to see the biggest advantage (or one of the biggest advantages) of passing them by value vs by const&: in both cases you protect the actual entity at the call site, but in the latter you avoid copying a potentially huge object.

For pointer-like entities such as raw pointers and smart pointers, I look at them as things which are meant to be at least similar in size to each other, with the std::shared_ptr allowed to diverge from the similarity.

Anyway, if we are dealing with obviously small raw pointers and std::unique_ptrs and small std::shared_ptrs, so that we can consider the aforementioned advantage of passing by const& negligible, is there any other reason why I might want to pass them by const&?

CodePudding user response:

Without a reference you cannot overload a function based on constness of the parameter:

void foo(int* const) { /* do something */ }
void foo(int*) { /* do something else */ }  // error : redefinition of foo

But you can do so with a const/non-const reference:

void bar(int*&) { std::cout << "non-const\n";}
void bar(int* const&) { std::cout << "cosnt\n";}

int main() {
    int* y = nullptr;
    int* const x = nullptr;
    bar(y);
    bar(x);
}

CodePudding user response:

To answer the title of your question, for raw pointers, no. Passing by a pointer by reference is usually more expensive, and if it's a const reference you can't use it to modify the caller's pointer anyway so there's no benefit (and I really don't know what @463035818_is_not_a_number is getting at, who would want ever such overloads?)

For a smart pointer it's different. std::unique_ptr cannot be passed by value at all (since the copy constructor is deleted) so you can either pass by reference (if you just want to get at what it's pointing to) or you can move from it (to transfer ownership). And in fact, there's not really much point in passing it by const reference since you can pass my_unique_ptr.get() as a raw pointer - by value - and not lose anything.

std::shared_ptr can be passed by value, but doing that will bump the reference count (and then decrement it again when the copy goes out of scope), and there is a cost associated with that so you might want to pass it by const reference since that may well be cheaper. But, again, if the function you're calling is non-owning, why not just pass a raw pointer? This is the cheapest option of all.

The only reason to copy a shared_ptr is to make sure that the pointer it is managing does not disappear out from beneath you, and that implies you're hanging on to it for some reason (so-called 'shared ownership'). So yes, if that's the semantics you want, pass it by const reference and make a copy at the receiving end.

  • Related