我正在做 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);
跟踪2c.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();
}
和跟踪.c
CTraceSpan *span = NULL;
span = c_StartClientSpan();
c_FinishClientSpan(span);
当我运行我的项目时,我收到一个错误:
分段故障(核心转储(
下面的问题,说不能从原始指针创建shared_ptr,但是我需要将指针形式C传输到C ++,该怎么办?
使用shared_ptr时的分段错误
您永远不应该像这里那样从普通指针创建shared_ptr:
shared_ptr<ParticleEmitter>(&e)
这会尝试释放粒子发射器两次。一次是作为包含粒子发射器对象的矢量超出范围,一次是作为shared_ptr超出范围。
下面的问题,说不能从原始指针创建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++。您的示例不完整,并且不清楚您打算如何使用共享指针。
如果已经有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();
}
shared_ptr
用于共享对象的所有权。如果它已由其他人拥有和管理,则可以将引用或非拥有指针传递给该对象。
如果所有权确实是共享的,你可以在"保存粒子发射器的向量"中存储一个shared_ptr
,然后传递该shared_ptr
的副本,以便最后一个用户处理删除。