首页 > 解决方案 > 如何从原始指针中获取 shared_ptr?

问题描述

我在做 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);

跟踪2cpp

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++,我该怎么办?

使用 shared_ptr 时出现分段错误

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

shared_ptr<ParticleEmitter>(&e)

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

标签: c++csegmentation-fault

解决方案


下面的问题说不能从原始指针创建 shared_ptr

该特定答案通常是错误的(尽管在特定情况下是正确的)。您可以从原始指针创建共享指针。您不能从不拥有该对象的指针创建共享指针。

但我需要将指针从 c 传输到 c++,我该怎么办?

这取决于。指向的对象是如何分配的?是否需要手动解除分配(即它是动态分配的)?什么时候应该(什么时候不能)释放它?谁应该负责释放(C 或 C++)?应该如何释放它(这应该直接取决于它是如何分配的)?

如果对象是静态的或自动的,那么您不需要特别做任何事情。

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

假设对象是在 C 中使用 分配的malloc,并被赋予负责释放的 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++ 中分配。您的示例不完整,并且不清楚您打算如何使用共享指针。


推荐阅读