我正在进行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超出范围。
答案 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();
}