ansyser
ansyser

Reputation: 3

How to get shared_ptr from raw pointer?

I'm doing c/c++ mix programming, like this:
common.h

#ifdef __cplusplus
typedef opentracing::Span CTraceSpan;
#else
struct CTraceSpan;
typedef struct CTraceSpan CTraceSpan;
#endif

extern "C" CTraceSpan* c_StartServerSpan();
extern "C" CTraceSpan* c_FinishServerSpan(CTraceSpan *span);

trace2c.cpp

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

extern "C" CTraceSpan* c_FinishServerSpan(CTraceSpan *span){
std::shared_ptr<opentracing::Span> s_span(std::move(span));

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

and in trace.c

CTraceSpan *span = NULL;
span = c_StartClientSpan();
c_FinishClientSpan(span);

when I run my project, I got an error:

Segmentation fault (core dumped)

the question below, said that can't create shared_ptr from an raw pointer, but I need to transmit a pointer form c to c++, what should i do?

Segmentation fault when using a shared_ptr

You should never create shared_ptr from an ordinary pointer as you do here:

shared_ptr<ParticleEmitter>(&e)

This tries to free the ParticleEmitter twice. Once as the vector holding the ParticleEmitter objects goes out of scope, and once as the shared_ptr goes out of scope.

Upvotes: 0

Views: 11376

Answers (3)

eerorika
eerorika

Reputation: 238311

the question below, said that can't create shared_ptr from an raw pointer

That particular answer is wrong in general (although correct in that specific case). You can create a shared pointer from a raw pointer. You just can't create a shared pointer from a pointer that doesn't own the object.

but I need to transmit a pointer form c to c++, what should i do?

It depends. How was the pointed object allocated? Does it need to be deallocated manually (i.e. was it allocated dynamically)? When should (and when can't) it be deallocated? Who should be responsible for the deallocation (C or C++)? How should it be deallocated (which should directly depend on how it was allocated)?

If the object is static or automatic, then you need to do nothing in particular.

How to get shared_ptr from raw pointer [from C]?

Assuming the object was allocated in C using malloc, and is given to C++ code that is responsible for deallocation, then like this:

std::shared_ptr<CTraceSpan> s_span(span, std::free);

It is usually bad API design to allocate something, and push the responsibility of figuring out how to deallocate to the client code. So, for every function that allocate something, usually a C API will have a deallocation function that allows the client to decouple from specifics of deallocation. This is particularly important when the allocated object itself has owning pointers dynamic memory.

Assuming deallocate_ctrace_span is such deallocation function in this case:

std::shared_ptr<CTraceSpan> s_span(span, deallocate_ctrace_span);

All that said, it appears that your pointers aren't actually allocated in C, but rather C++. Your example isn't complete, and it's unclear how you intend to use the shared pointer.

Upvotes: 4

Caleth
Caleth

Reputation: 62616

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();
}

Upvotes: 2

Bo Persson
Bo Persson

Reputation: 92231

A shared_ptr is for sharing ownership of an object. If it is already owned and managed by someone else, you can pass a reference or non-owning pointer to that object.

If the ownership really is shared, you could store a shared_ptr in " the vector holding the ParticleEmitter", and then pass copies of that shared_ptr so that the very last user will handle the delete.

Upvotes: 1

Related Questions