Creating Shared_Ptr from Raw Pointer

How to get shared_ptr from raw pointer?

If there are already shared_ptrs owing those CTraceSpans, you can't create a new shared_ptr from the raw pointer. Otherwise you would have two ownership relations to the CTraceSpan, and undefined behaviour after one of them frees the CTraceSpan.

The implementation of c_FinishServerSpan is going to have to have to go find an existing std::shared_ptr<CTraceSpan>, such that it's underlying pointer is equal to span.

static std::map<CTraceSpan*, std::shared_ptr<CTraceSpan>> spans;

extern "C" CTraceSpan* c_StartServerSpan(){
auto server_span = hwtrace::StartServerSpan();
spans[server_span.get()] = server_span;
return server_span.get();
}

extern "C" CTraceSpan* c_FinishServerSpan(CTraceSpan *span){
auto s_span = spans.at(span);
// spans.erase(span) ?

auto server_span = hwtrace::FinishServerSpan(s_span);
spans[server_span.get()] = server_span;
return server_span.get();
}

Returning smart pointer from raw pointer

The term "correct" is quite vague. Ok, this code should work, if you ask of that. However there are more details you should take into consideration.

First, it is better to construct the object in the same expression where you construct the smart pointer:

std::shared_ptr<Geometry> Clone() const
{
return std::shared_ptr< Geometry >(new Circle(*this));
}

Why so? Imagine that you add one more line of code in between, and this code throws an exception... That is the benefit of smart pointers that they prevent you from memory leaks like that, and you loose this benefit in your initial version of code.

Next, I don't see the definition of the class Geometry, and it probably has a virtual destructor... But what if it doesn't? Which class would the shared_ptr destroy? The answer is: the class that shared_ptr knows. Ok, in your code there is a way for shared_ptr to get known that the actual class is class Circle (because of the shared_ptr constructor, that knows exactly the actual class of the underlying object), but it is very easy to make a mistake. One-liner solves this issue.

But there is one more (possible) improvement: std::make_shared:

std::shared_ptr<Geometry> Clone() const
{
return std::make_shared< Circle >(*this);
}

In this case you allocate memory only once, for both the object and the counter structure. That works better unless you employ std::weak_ptr. You should be very careful using both std::make_shared and std:weak_ptr: the actual memory deallocation of the shared counter (which is the same memory that is used for the object itself in case of std::make_shared) will be done only after the last weak_ptr is destroyed. That could cause some sort of a memory leak.

So the way you use it is correct, but there is not enough information to judge what is the best idiomatic way to do that.

Making shared_ptr from the raw pointer of another shared_ptr

Unless you have a constructor that takes A* as only argument, your line won't event compile.

If you do have a constructor A::A(A*), then make_shared will create a new object - this is fine.

If you would use std::shared_ptr constructor instead:

std::shared_ptr<A> ptrSecond = std::shared_ptr<A>(ptrFirst.get());

then it is a problem. It will result in double deallocation, which is UB.

Point raw pointer to a shared_ptr

I think this sounds like a good fit for std::enable_shared_from_this as Remy pointed out in the comments.

I whipped up a simplified example which hopefully makes it clear how it can be used to achieve what you're after.

class Intersection;

class IHittable : public std::enable_shared_from_this<IHittable> {
public:
virtual Intersection intersects( ) = 0;
virtual void print( ) const = 0;
virtual ~IHittable( ) = default;
};

class Intersection {
public:
Intersection( std::shared_ptr<IHittable> object )
: object_{ std::move( object ) }
{ }

void print_shape( ) const {
object_->print( );
}
private:
std::shared_ptr<IHittable> object_;
};

class Square : public IHittable {
public:
Intersection intersects( ) override {
return Intersection{ shared_from_this( ) };
}

void print( ) const override {
std::cout << "Square\n";
}
};

int main( ) {
std::vector<std::shared_ptr<IHittable>> objects{
std::make_shared<Square>( ) };

const auto intersect{ objects.front( )->intersects( ) };
intersect.print_shape( );
}

State of underlying resource when a shared_ptr is created from the raw pointer?

The paragraph is weirdly worded. If you remove this sentence:

If the callee creates a shared_ptr from the raw pointer, the new shared_ptr is independent from the original, and doesn't control the underlying resource.

It's fine. Indeed, talking about what would happen if the callee creates a new shared_ptr is something of a non-sequitur in this context.

This sentence is intended to be a warning not to create a shared_ptr from random pointers you get passed as arguments. The new shared_ptr is "independent from the original," but the rest of the sentence would be better stated as "and both of them will try to destroy the underlying resource". It's not so much that it doesn't "control" it; it's that it doesn't do so correctly.

C++ Using Raw pointer to std::shared_ptr

shared_ptr automatically increases and decreases its internally-stored reference count when you copy it (using the assignment operator=), and - importantly - when a shared_ptr is destroyed (by going out of scope). Your approach for transmitting a pointer-to-shared-pointer is fundamentally flawed in the code above, because you are transmitting the address of a temporary shared pointer, but not the ownership or lifespan. The shared_ptr - which is still owned by Thread A - might go out of scope and be destroyed before Thread B can use it.

In order to transfer ownership of a shared_ptr instance, I would suggest creating a heap-allocated/dynamic shared_ptr for transfer. This can be accomplished using new or (even better) make_unique. Using a unique_ptr (i.e.: unique_ptr<shared_ptr<ObjectClass>>), you would use the 'release' method, before passing the pointer across the thread barrier in your message.

Thread A:

auto sharedPtr = std::make_shared<ObjectClass>();

// This line creates a heap-allocated copy of a
// shared_ptr (incrementing reference count)
// And places ownership inside a unique_ptr
auto sharedPtrDynamicCopy = std::make_unique<decltype(sharedPtr)>(sharedPtr);

// This 'releases' ownership of the heap-allocated shared_ptr,
// returning a raw pointer; it is now a potential
// memory leak!!! It must be 'captured' in Thread B.
auto rawPtrToPass = sharedPtrDynamicCopy.release();

Thread B:

// Here, we immediately 'capture' the raw pointer back
// inside a unique_ptr, closing the loop on the potential
// memory leak
auto sharedPtrDynamicCopy = unique_ptr<shared_ptr<ObjectClass>>(rawPtrFromThreadA);

// Now we can make a copy of the shared_ptr, if we like.
// This sharedCopy will live on, even after recvdPtr goes
// out of scope.
auto sharedCopy = *sharedPtrDynamicCopy;

You could perhaps shorten this further by simply 'new'-ing a raw shared_ptr instead of capturing it inside a unique_ptr<shared_ptr<T>>, but I personally prefer this approach since it has clear "capture" and "release" semantics for the pointer-in-flight.

C++ make::shared wrapping on existing raw pointer

You're passing a pointer where you should pass a reference. Try *sound.

Notice that you're not wrapping a pointer, you're creating a new instance of Sound and copying the value of *sound into it.

To wrap it consider:

data.mFmodSoundHandle.reset(sound);


Related Topics



Leave a reply



Submit