2008-12-02 4 views
11

우리는 여러 다른 클라이언트에 제공하는 C++ 라이브러리가 있습니다. 최근에 공용 인터페이스에서 raw 포인터를 사용하는 대신 boost :: sharedptr을 사용하도록 전환했습니다. 이제는 고객이 더 이상 언제 어디에서 삭제할 필요가 있는지 걱정할 필요가 없으므로 이로 인해 엄청난 이점을 얻을 수 있습니다. 전환 작업을 수행 할 때는 올바른 일이라고 생각했지만 공개 인터페이스에 제 3 자 라이브러리의 항목을 포함시켜야한다는 것을 귀찮게했습니다. 일반적으로 가능한 한 그런 일을 피하십시오. 나는 부스트가 사실상 C++ 언어의 일부 였다고 합리화했다. 우리의 유스 케이스에서는 클라이언트 코드와 라이브러리가 객체에 대한 포인터를 가지고 있어야한다. 그러나 최근에 우리 고객이 인터페이스에 중립 스마트 포인터 클래스를 사용하도록 전환 할 수 있는지 물어 보았습니다. 왜냐하면 우리 도서관이 본질적으로 그들이 분명히 이해하고 높이 평가하는 특정 버전의 부스트를 강요하기 때문입니다. 그래서 지금 나는 최선의 행동이 무엇인지 궁금해하고 있습니다. 나는 그것에 대해 조금 생각해 보았고 간단하게 스마트 포인터를 높이는 간단한 스마트 포인터 클래스를 만드는 것에 대해 궁금해했습니다. 그러나 클라이언트는 아마 boost :: sharedptr의 맛을 보게 될 것입니다. 그리고 나서 우리는 세 개의 공유 된 포인터가 될 것입니다. 이것은 문제가 될 수도 있고 그렇지 않을 수도 있습니다. 어쨌든이 문제를 해결하는 가장 좋은 방법에 대한 의견을 듣고 싶습니다.라이브러리의 공용 인터페이스에서 boost :: shared_ptr 사용

편집 : 처음에는 소유권 이전을했지만 API 경계 양쪽에있는 코드는 객체에 대한 포인터를 보유해야한다고 지정 했어야합니다.

답변

13

공유 _ptr <>은 TR1의 릴리스 시점에서 언어의 일부입니다 (). 참조 : (TR1)

+1

그렇습니다. 그러나 TR1이 포함 된 Visual Studio 2008, IIRC로 클라이언트를 이동시킬 수는 없습니다. 일부는 여전히 VS 2005에 있습니다. –

+1

라이브러리 헤더에 Boost TR1 폴더를 포함시킬 수 있습니까? 그게 합법적인지 알아보기 위해서는 면허증을 봐야 겠지만, 아마도 그렇습니다. boost :: shared_ptr <>은 단순한 템플릿이기 때문에 공유 라이브러리 나 정적 라이브러리가 필요하지 않습니다. –

+2

TR1은 언어의 일부는 아니지만 향후 언어 표준의 일부가 될 수있는 (공식적인) 정보 수집 모음입니다. 여기를 참조하십시오 : http://www.iso.org/iso/standards_development/processes_and_procedures/deliverables/iso_tr_deliverable.htm –

4

이것은 C++입니다. 공유 포인터 구현을 통해 인터페이스 클래스를 템플릿으로 만들 수 있습니다.

+2

... 따라서 템플릿이 필요하기 때문에 인터페이스 구현을 숨길 수 없습니다. 독점 소프트웨어를 판매하려는 누군가를위한 좋은 생각이 아닙니다. – Bklyn

+0

@Bklyn : 적어도 스트립 팩 된 소스가 없으면 써드 파티 C++ 라이브러리를 사용하지 않을 것입니다. C++ ABI는 너무 연약합니다. – Joshua

6

의미가 실질적으로 소유권 전환 인 경우이면 표준 C++이기 때문에 auto_ptr을 사용하지 않는 이유는 무엇입니까? 내부적으로 auto_ptr에서 shared_ptr을 생성 한 다음 필요한 경우 소유권을 공유 할 수 있습니다.

3

boost copy 유틸리티를 사용하면 스마트 포인터 클래스 만있는 부스트 버전을 빌드 할 수 있습니다. 스마트 포인터 클래스는 헤더 전용 라이브러리이기 때문에 라이브러리에 포함 할 수있는 헤더가 몇 개 있어야합니다.

18

하나의 가능한 솔루션은 프로젝트에 boost :: shared_ptr을 제공하는 것입니다. 모두 헤더로 구성되어 있기 때문에 클라이언트가 수동으로 부스트 라이브러리를 설치하지 않아도됩니다. bcp을 사용하면 라이브러리를 포함하여 특정 부스트 라이브러리에 필요한 모든 파일을 가져올 수 있습니다. 나는 당시 그 회사에서 일했을 때 boost::shared_ptr을 필요로했으며 실제로 효과가있었습니다.

3

이것은 내가 잠시 동안 가지고 있었던 흥미로운 질문입니다. 사용자가 제공하는 라이브러리에 사용자를 강제로 배치합니까, 아니면 프로젝트에서 무엇이 최선인지 결정할 수있게합니까? 언제나처럼, 질문은 당신이 제공하는 것과 사용자가 요구하는 것입니다.

원시 포인터를 사용하는 경우 모든 종류의 가능성을 허용합니다. 사용자 코드는 원시 포인터를 사용하여 std :: auto_ptr, shared_ptr (boost 또는 TR1) 또는 스마트 포인터의 자작 버전에 저장할 수 있습니다. 그러나 이것은 메모리를 해제하는 것을 잊어 버리면 사용자를 곤경에 빠뜨릴 수 있으며, 메소드 호출을 위해 임시로 생성하기를 원한다면 더 많은 코드가 필요합니다 (원시 포인터를 제공하면, 비 임시 [가능하다면 스마트] 포인터 변수에있는 포인터).

이제 스마트 포인터를 사용하면 솔루션을 사용자에게 강제 적용하게됩니다. 스마트 포인터의 자체 버전을 사용할 계획이라면 (boost :: shared_ptr을 사용하고 std :: tr1 :: shared_ptr을 원한다고 말하면) 인터페이스와 함께 작동하는 경우 더 이상 사용할 수 없습니다. 어떤 스마트 포인터 (std :: auto_ptr는 특별한 것 외에)를 결정하더라도 솔루션을 강요 할뿐만 아니라 문제도 있습니다.

사용자가 다중 스레드 응용 프로그램을 사용하고 있고 솔루션이 스레드 안전하지 않은 경우 사용자는 안전하지 않은 솔루션에 바인딩됩니다. 반면에 스마트 포인터가 스레드 안전하지만 잠금 비용이 발생하면 다중 스레드 응용 프로그램에서 작업하는 경우에도 해당 비용이 사용자에게 적용됩니다. 헤더 만의 lib가 아닌 라이브러리를 컴파일하면 스마트 포인터 라이브러리의 변경으로 인해 코드의 호환성이 깨질 수 있으므로 스마트 포인터 유형뿐만 아니라 특정 버전의 라이브러리도 필요합니다.

부수적으로, boost :: shared_ptr (boost 1.33+)은 대부분의 경우 thread safe이고 많은 플랫폼에서 잠금없는 구현을 사용합니다. 어쨌든 이것은 당신에게 당신이 고려해야 할 것들에 대한 아이디어를 줄 것입니다.

마지막으로 스마트 포인터 유형을 사용하여 사용자를 바인딩 할뿐만 아니라 동일한 버전을 사용하는 것으로 간주해야합니다. 특정 버전의 boost에 대해 lib를 컴파일하면 해당 특정 구현에 바인딩됩니다.

6

우선 라이브러리를 컴파일 된 라이브러리가 아닌 소스 코드로 배포하면이 대답을 무시할 수 있습니다. 또한 다른 플랫폼과 관련이 없을 수있는 특정 Windows 관련 문제가 있습니다.

저는 개인적으로 당신이 도서관에서 공용 인터페이스에 너무 많은 펑키 한 C++를 피하는 것이 좋습니다. 클라이언트에서 많은 문제를 일으킬 수 있기 때문입니다.

내가 어떻게 적용 할 수 있는지 잘 모르겠지만, 개인적으로 내가 사용했던 stl 라이브러리의 심볼이 새 버전으로 업그레이드했을 때 제 3 자 라이브러리의 심볼과 충돌하는 문제가 발생했습니다. . 이것은 우리가 이상한 곳에서 충돌을 일으켰다는 것을 의미했고 나는이 문제를 피하기 위해 많은 트릭을해야했습니다. 결국 나는 이것 때문에 도서관의 구버전에 머물렀다.

다른 문제는 다른 C++ 컴파일러가 동일한 기호를 다르게 조작 할 수 있다는 것입니다. 즉, 동일한 Boost 버전을 사용하는 경우에도 지원하려는 모든 컴파일러에 대해 별도의 라이브러리를 제공해야 할 필요가 있음을 의미합니다. 이것에 대한 토론은 "Imperfect C++"책을 확인하십시오.

다른 C++ 컴파일러와 환경의 세계에서 슬픈 진실은 인터페이스에 C가 있으면 안되며 라이브러리를 동적으로 연결해야한다는 것입니다 (고객 링크를 연결할 때 충돌을 피하기 위해 라이브러리 링크 , 윈도우 런타임 라이브러리가 진짜 고통이 될 수 있습니다 여기). 당신은 당신의 기호가 dll의 고객 환경으로부터 격리 될 것이기 때문에 당신이 원하는만큼 라이브러리의 내부에서 여전히 부스트와 멋진 C++를 사용할 수 있습니다.

라이브러리의 인터페이스에 스마트 포인터와 다른 멋진 C++ 기능을 실제로 갖고 싶다면 소스 코드를 배포하는 편의 층을 구축하십시오. 이렇게하면 항상 고객 환경에서 컴파일됩니다. 이 인터페이스는 노출 된 C 함수를 영리하게 호출합니다. 그 레이어에서 부스트를 사용하는 것은 좋지 않다고 생각합니다. 고객이 원치 않더라도 그것을 채택하도록 강요 할 것이기 때문입니다. 그러나 레이어를 소스로 배포 했으므로 바꾸거나 다른 솔루션을 찾기가 쉽습니다. 암호.

또 다른 멋진 기능은 C/C++ 이외의 다른 언어로 라이브러리를 노출하려는 경우 일반적으로 dll에서 C 함수를 호출하는 것이 이상합니다.

이 방법을 사용하면 다양한 방식으로 인생을 더욱 복잡하게 만들 수 있지만, 사람들이 자신의 코드와 성공적으로 연결할 수 없기 때문에 사람들이 라이브러리를 피할 가능성을 줄이는 방법입니다.

1

boost :: shared_ptr을 도입하면 클라이언트가 부스트를 사용해야합니다. 어떤 사람들에게는 이것이 사소한 문제입니다.

또한 lib가 컴파일 된 바이너리로 배포되는 경우 클라이언트가 lib에서 사용하는 것과 동일한 컴파일러를 사용해야합니다. 또는 라이브러리가 소스 코드로 배포되는 경우 클라이언트는 lib를 컴파일하는 데 사용되는 컴파일러를 선택해야합니다. 이것은 상당한 규모의 프로젝트에서 사소한 문제는 아닙니다.

1

auto_ptr을 사용하거나 C 인터페이스에 고정하십시오. C++ 라이브러리를 당신의 인터페이스에 억지로 넣는 것은 항상 못 생기고, 크로스 플랫폼이 될 가능성을 없애며, 다른 "다운 스트림"구성을 가진 고객들에게는 유지 보수의 악몽을 불러 일으 킵니다.

클라이언트가 C++ 0x를 주류로 사용하는 즉시 std::shared_ptr으로 전환하십시오.

관련 문제