如何从原始指针获取shared_ptr?

时间:2018-05-25 09:45:38

标签: c++ c segmentation-fault

我正在进行c / c ++混音编程,如下所示:
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();
}

和trace.c

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

当我运行我的项目时,我收到了一个错误:

分段错误(核心转储)

下面的问题,说不能从原始指针创建shared_ptr,但是我需要将指针形式c传递给c ++,我该怎么办?

Segmentation fault when using a shared_ptr

  

你不应该像在这里那样从普通指针创建shared_ptr:

shared_ptr<ParticleEmitter>(&e)
     

这会尝试释放ParticleEmitter两次。一旦持有ParticleEmitter对象的向量超出范围,一旦shared_ptr超出范围。

3 个答案:

答案 0 :(得分:3)

  

下面的问题,表示无法从原始指针创建shared_ptr

一般来说,这个特定答案是错误的(虽然在特定情况下是正确的)。您可以从原始指针创建共享指针。您无法从不拥有该对象的指针创建共享指针。

  

但是我需要将指针形式c传递给c ++,我该怎么办?

这取决于。如何分配尖头物体?是否需要手动解除分配(即动态分配)? 应该(何时不能)被解除分配?谁应该负责解除分配(C或C ++)?应该如何解除分配(哪个应该直接取决于它的分配方式)?

如果对象是静态的或自动的,那么你需要特别做什么。

  

如何从原始指针[来自C]获取shared_ptr?

假设对象是使用malloc在C中分配的,并且给予负责解除分配的C ++代码,那么就像这样:

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

分配内容通常是错误的API设计,并且负责确定如何解除分配给客户端代码。因此,对于分配内容的每个函数,通常C API将具有释放函数,该函数允许客户端从解除分配的细节中解耦。当分配的对象本身拥有指针动态内存时,这一点尤为重要。

假设deallocate_ctrace_span在这种情况下是这样的释放函数:

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

所有这一切,似乎你的指针实际上并没有在C中分配,而是C ++。您的示例不完整,并且不清楚您打算如何使用共享指针。

答案 1 :(得分:1)

shared_ptr用于共享对象的所有权。如果它已由其他人拥有和管理,则可以将引用或非拥有指针传递给该对象。

如果所有权真的 共享,您可以在“持有ParticleEmitter的向量”中存储shared_ptr,然后传递shared_ptr的副本以便非常最后一个用户将处理删除。

答案 2 :(得分:0)

如果shared_ptr已经CTraceSpan,那么您无法从原始指针创建新的shared_ptr。否则,您将拥有CTraceSpan的两个所有权关系,并且在其中一个与CTraceSpan之后释放未定义的行为。

c_FinishServerSpan的实现必须找到现有的 std::shared_ptr<CTraceSpan>,这样它的底层指针就等于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();
}