10

I faced a problem with std::shared_ptr. I have a code:

void Receive(const std::shared_ptr<char[]>& data, uint32_t length) {
  this->next->Receive(data + 2, length - 2);
}

I need to increment shared_ptr by 2 without losing the ability to delete the memory.

I don't want to copy data, because the data is already in memory and I own the data. It would be foolish to copy the data just to displace and delete the old data if I can just change the pointer without losing performance. Can shared_ptr contain and return one pointer, but delete another?

As far as I know, the internals of shared_ptr contains a pointer to data which is returned by the get() function and contains a reference to a control block that counts references and is supposed to delete the memory when all references have gone.

So, since it contains pointer separately from control block, maybe I can somehow change it without changing the pointer to the allocated memory block in the control block, without losing the ability to delete the memory? If I can't, maybe I can do it with boost::shared_ptr?

I haven't checked it yet. I don't use the Boost library, but if it helps me I will.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zenno2
  • 425
  • 2
  • 7
  • 2
    Could you perhaps use `void Receive(char* data, uint32_t length)` instead? Or even consider `void Receive(std::span data);`. – Galik Jul 13 '21 at 15:20

1 Answers1

15

Yes, that's what the aliasing contructor of std::shared_ptr is for. It keeps the same control block, but it allows you to use another pointer.

The signature is

template< class Y >
shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;

In your case that would be

void Receive(const std::shared_ptr<char[]>& data, uint32_t length) {
  std::shared_ptr<char[]> alias(data, data.get()+2);
  this->next->Receive(alias, length - 2);
}

But I do question the use of shared_ptr in this case. Do you really have shared ownership in this case? Can you not figure out one part of code that could own this memory?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
PeterT
  • 7,981
  • 1
  • 26
  • 34
  • I'd be tempted to bubdle offset, length and shared ptr to buffer into a struct myself. Implement + and ++ and length remaining and the like. Also unary star and arriw dereference. Overhead is modest, and debugging far more friendly. Plus ptr and length are one bundle, not two arguments, – Yakk - Adam Nevraumont Jul 13 '21 at 14:53
  • 1
    @Yakk-AdamNevraumont for another use-case maybe. But the function as specified would work better with just taking a `char*` and letting the call-site do the `sptr.get()` call. Because it's passing a `const std::shared_ptr&`, so taking it by reference and not even taking part in ownership. In this case (as presented) using shared_ptr did nothing good – PeterT Jul 13 '21 at 15:22
  • I mean, in theory, the call to `next->Recieve` could thread off the reading and take ownership from the passed in shared ptr, and return immediately, for example. – Yakk - Adam Nevraumont Jul 13 '21 at 15:35