2016-10-13 4 views
9

C의 C++ 라이브러리에서 일부 API를 래핑해야합니다. 예를 들어 here과 같이 클래스 개체, extern "C"등에 대한 불투명 포인터를 사용하여이 작업을 수행했습니다. 그러나이 새로운 라이브러리는 참조 계산 스마트 포인터를 광범위하게 사용합니다. 스마트 포인터가있는 상태에서 랩핑을 수행하는 방법을 잘 모르겠습니다.C에서 스마트 포인터를 반환하는 C++ 함수를 어떻게 랩핑합니까?

SmartPointer<MyClass> foo() { 
    SmartPointer<MyClass> ret(new MyClass); // Create smart pointer ret 
    ret->DoSomething(); // Do something with ret 
    return ret; 
} 

어떻게 C에서 foo()을 포장 할 수 있습니다 : 예를 들어,이 C++ 라이브러리는 다음과 같은 기능을 가지고 가정 해 봅시다? 분명히, 내가 MyClass 개체를 참조하는 C 함수에서 사용할 수있는 불투명 한 포인터 (예 : void* 또는 빈 구조체 포인터)가 필요합니다. 내가 생각한 첫 번째 옵션은 ret에서 MyClass 개체를 추출하여 void*으로 전송하는 것입니다. 그러나이 void*은 스마트 포인터 (잘못된 경우 올바른 수정)로 자동 삭제로 인해 범위 밖으로 나가면 ret이 매달리게됩니다.

다른 옵션은 스마트 포인터 (예 : retPtr)에 포인터를 할당하고 *retPtr=ret을 수행 한 다음 retPtr에 대한 불투명 포인터를 생성하는 것입니다. 나는이 옵션이 효과가있을 것이라고 생각하지만 이것이 최선의 방법인가?

도움을 주시면 감사하겠습니다.

+3

지난 제안에 동의합니다. –

+3

어떤 종류의 스마트 포인터, stdlib에 SmartPointer라는 클래스가 없다는 것을 알고 있습니다. 이것은 엄청나게 문제의 스마트 포인터의 의미에 달려 있습니다 ... – Vality

+0

C 라이브러리는 실제로'ObjectType'의 멤버에 액세스해야합니까? 아니면 잠시 동안 포인터를 잡고 나중에 놓을 수 있습니까? 또한'ObjectType'과'MyClass' 사이의 관계는 무엇입니까? –

답변

1

이 주석은 C 코드가 스마트 포인터를 보유해야하지만 다른 C++ 함수로 그대로 전달하는 것 외에는 아무 것도 할 필요가 없음을 나타냅니다.

// Shared header 
#ifdef __cplusplus 
extern "C" { 
#endif 

void * foo_acquire(void); 
int foo_bar(void *); 
void foo_release(void *); 

#ifdef __cplusplus 
} 
#endif 

// C++ implementation 
extern "C" void *foo_acquire() 
{ 
    return new SmartPointer<MyClass>(foo()); 
} 

extern "C" int foo_bar(void *s) 
{ 
    auto& sp = *static_cast< SmartPointer<MyClass> * >(s); 
    return bar(sp); // bar represents some function expecting the smart pointer 
} 

extern "C" void foo_release(void *s) 
{ 
    delete static_cast<SmartPointer<MyClass> *>(s); 
} 

이것은 SmartPointer의 이동-생성자를 사용하여 (또는 복사 생성자가 입주 생성자를 가지고 있지 않은 경우), 스마트 포인터에 의해 지원 될 필요가 작업을 : 그 코드는 수 있습니다.

C 코드에서 암시 적 변환을 방지하려면 void * 대신 불투명 한 핸들을 사용할 수 있습니다. (예 : 회원으로 void *의 구조체).

5

당신은 C 코드에 불투명 한 포인터를 반환해야합니다. 따라서 new을 사용하여 포인터를 반환 할 수있는 새로운 스마트 포인터를 할당해야합니다.

유일한 대안은 공유 포인터 모음을 사용하여 개체를 유지하는 것입니다. C 코드가 객체로 끝났음을 나타내면 콜렉션에서 공유 포인터를 제거합니다. 이렇게하면 C 코드에 필요한 모든 종류의 식별자를 반환 할 수 있습니다.이 식별자는 컬렉션의 객체를 찾기위한 핸들로 사용됩니다.

+1

핸들의 개념은 좋은 생각이다. 결국'FILE'이 C에서 어떻게 작동하는지 알 수있다. –

2

David Schwartz의 답변 외에도 COM의 IUnknown과 비슷한 접근법을 고려할 수 있습니다. 함수 포인터 (순수한 C에서 C++ 인터페이스를 시뮬레이트 함)를 포함하는 구조체를 정의하고 AddRef 및 Release와 같은 몇 가지 메소드를 노출하여 참조 계수를 높이거나 해제 할 수 있습니다.

호출자는 해당 구조에 대한 포인터를 가져 오므로 AddRef 및 Release를 사용하여 반환 된 객체의 적절한 수명을 제어 할 수 있습니다.

또한 구조체에 다른 메소드 (함수 포인터)를 추가하여 반환되는 객체의 다른 기능을 노출 할 수 있습니다.

This article on COM in plain C은 자세히 설명합니다.

0

구조체를 포인터가 아닌 C 코드에 노출 시키십시오.상기 구조체에서, 포인터와 포인터의 상태에 대한 표시기를 가져라. 구조체를 인식하도록 동작을 스마트 포인터에 추가하십시오. struct는 포인터와 할당 된 객체의 상태를 모두 포함합니다. 따라서 스마트 포인터의 추가 동작은 구조체에서 할당 된 객체의 상태를 업데이트해야합니다 (예 : 스마트 포인터가 할당 취소를 수행 할 때 일부 값으로 설정).

0

이 주석은 C 코드가 무언가를 보유하고 SmartPointer을 C++ API에 전달해야 함을 나타내지 만 그대로 다른 C++ 함수로 전달하는 것 외에는 아무 것도 할 필요가 없습니다.

EnableSharedFromThis에서 MyClass inherite을 확인하십시오 :

struct MyClass : public EnableSharedFromThis, public AnotherBaseClass { 
//... 
}; 

를 공유 헤더 :

#ifdef __cplusplus 
extern "C" { 
#endif 

struct MyClass; 
MyClass * foo_acquire(void); 
int foo_bar(MyClass *); 
void foo_release(MyClass *); 

#ifdef __cplusplus 
} 
#endif 

C++ 구현을

나는 당신의이 EnableSharedFromThis을 가정 해 봅시다, 일부는 std::enable_shared_from_this처럼 생각 만들 필요가 있다고 생각합니다 :

List<SmartPointer<MyClass> > listToEnsureLifeTime; 
extern "C" MyClass * foo_acquire() 
{ 
    SmartPointer<MyClass> ptr = foo(); 
    listToEnsureLifeTime.Add(ptr); 
    return ptr.get(); 
} 

extern "C" int foo_bar(MyClass *s) 
{ 
    // bar represents some function expecting the smart pointer 
    return bar(s->SharedFromThis()); 
} 

extern "C" void foo_release(MyClass *s) 
{ 
    // I suppose this list can take difference SmartPointer with same 
    // inner have the same hash or something like that 
    listToEnsureLifeTime.erase(s->SharedFromThis()); 
} 
관련 문제