2010-12-13 2 views
18

긴 템플릿에 typedef를 사용하는 것과 관련하여 빠른 질문이 있습니다. 요점 : 나는 피클의 일부로 자신을 발견했다. 클라이언트 기능에 로컬이 아닌 typedef를 배치하는 것이 좋지 않은 것 같다. SO 개의 질문 (예 : here 참조)이 있지만 정확하게이 문제를 해결하지 못하는 것 같습니다. 이 질문은 다음에 typedef가 바람직한지 여부를 설명하지는 않습니다 - 설명의 목적으로 단순화하려고했습니다.공유 포인터를 typedef'ing하기위한 최상의 전략은 무엇입니까?

boost::shared_ptr<T>으로 작업하는 동안 내 문제가 발생했습니다. 기본적으로, 나는 다음을 수행 할 :

#include <boost/shared_ptr.hpp> 
typedef boost::shared_ptr<Widget> WidgetPtr; 

Widget 선언 헤더에이 형식 정의를 배치 못생긴 것 같다. (i) Widget 자체가 구성원에서 공유 포인터를 사용하지 않는 경우 추가 포함을 추가했습니다 (boost::shared_ptr 템플릿을 선언 할 수 없으므로 클래스를 수정하십시오. 다른 클래스 (클래스 Foo)를 선언 할 때이 typedef를 사용하려면 Widget을 선언하거나 WidgetFwd.h을 단순히 전달하는 대신 Widget.h을 포함하여 권장 사항을 위반합니다. typedef는 후자에서 중복됩니다. 또한 Widget 선언 중에 typedef boost::shared_ptr<Widget>을 typedef하는 것은 의미가없는 것처럼 보입니다. Widget의 선언문을 클라이언트가 Widget 인터페이스를 어떻게 사용할 것인지를 예상하여 혼합하는 것처럼 보입니다.

그래, 나쁘다.하지만 이것은 더 나쁘다 : 위의 몇 가지 조합을 시도하지 않으면 클라이언트 코드에서 중복 typedef가 생기게되어 불일치 (따라서 오류 가능성이 있음) - 전체 요점은 주어진 Widget, WidgetPtr typedef 자체 유형으로 행동해야한다는 것입니다. 예 : Fooboost::shared_ptr의 typedef 인 WidgetPtr을 사용하지 않고 Barstd::auto_ptr의 typedef로 WidgetPtr을 사용합니다.

또 다른 방법은 (내가 온라인 토론에서 언급 본 적이 그 몇 가지 중 하나)이 타입 정의를 Widget의 공개 구성원으로하는 다음 Widget::Ptr 사용한다 : 다시

class Widget { 
// ... 
public: 
    typedef boost::shared_ptr<Widget> Ptr; 
}; 

을, 나는 '돈 (i) 이것은 포인터 타입이 어떻게 든 클래스의 멤버이고 (ii) 포인터가 우스꽝스러운 인터페이스로 연결된다는 것을 암시한다. 더욱 나쁜 것은 : 필자가 작성한 모든 클래스는 스마트 포인터를 사용하여 잠재적으로 지적 될 수 있기 때문에, 나는 가상의 클라이언트의 꼬리를 쫓아 가게된다. 추악하고 못생긴 추한.

필자는이 코드베이스에서 typedef를 제거하고 (심각한 혼란과 중복을 가져 왔기 때문에) 선택된 함수에서 로컬로 다시 도입했습니다. 여기에도 일관성없는 사용법에 대한 문제가 있지만 심각한 것은 아닙니다.

내가 생각할 수있는 또 다른 해결책은 이것이 좋은 연습으로 간주되는지 확실하지 않습니다. typedef가있는 유틸리티 헤더를 잠재적으로 자체 네임 스페이스 내에 배치하는 것입니다. 이 머리말에서 우리는 그것을 포함하고 끝낼 것입니다.

나는 명백한 것이 없거나 그냥 까다 롭습니다.

PS- 위의 길이에 대한 사과; 문제를 완전히 표현할 수있는 더 간단한 방법을 찾지 못했습니다.

+2

처음에 이것을 typedefing하는 이유는 무엇입니까? 'shared_ptr '이라는 이름은 매우 간단하며 위젯에 대한 공유 포인터입니다. – Kos

+0

@Kos : 그냥 위젯 대신 위젯 같은 것이 있으면 문제가 발생한다고 생각합니다. 유형이 화면에 맞지 않는 한 빨리 typedef'ing :-) – Philipp

+0

앞으로 공유 포인터를 변경하지 않으려면 typedefing이 매우 편리합니다. –

답변

6

특정 스마트 포인터의 사용을 지시하는 라이브러리가 마음에 들지 않지만 필요한 경우 허용합니다.

사용자가 항상 위젯을 조작하기 위해 shared_ptr을 사용하도록하려는 경우 불가능하기 때문에 시도하지 마십시오.

Widget의 메소드가 boost::shared_ptr<Widget>을 리턴하는 경우, (sane) typedef를 제공하면 클라이언트 코드가 단순해질 수 있습니다. 이 필요한 헤더를 #include 완벽하게 괜찮아

class Widget 
{ 
public: 
    typedef boost::shared_ptr<Widget> Ptr; 

    Ptr AccessFirstChild(); 
}; // class Widget 

하는 경우 :

그래서 저는 내부 타입 정의의 사용을 촉진한다.

+1

나는 또한 이것을 주장 할 것이고, 특히'위젯 (widget)'이 템플릿 화되어 있다면, 올바르게 작동하는 다른 접근법을 볼 수 없다. (즉,'Widget.h'의 typedef - 클래스 외부 - 예를 들어, 위젯의 모든 가능한 * 유형 *) – Nim

+0

원래 질문에서이 사례를 다루지는 못했을 것 같습니다. @ Nim의 관점에서 templatic 유형을 선호합니다. – Marc

+1

그래서 우리는 (느슨하게) 세 가지 경우가있는 것처럼 보일 것입니다 : (i) 편의를 위해 typedef ('Widget'은 멤버들 사이에서'shared_ptr' 인스턴스를 사용하지 않습니다) - 아마도 클라이언트에 의해 가장 잘 수행 될 것입니다; (ii) 템플릿 화 된'Widget'-here'Widget :: Ptr'에 대한 typedef는 의미가 있습니다; (iii) 멤버 정의의 편의를위한 typedef - 여기에서는 WidgetPtr가 이미 인터페이스의 일부이기 때문에 typedef를'Widget' 헤더에 두는 것도 의미가 있습니다; 'Widget'이 일반적이지 않은 경우, 우리는 클래스 선언 밖에서 typedef 할 수 있습니다. 공정한 요약? – Marc

5

당신은 내 의견으로는 이것을 생각하지 못했습니다. shared_ptr<Widget>을 갖고 싶어하는 모든 사람들은 어쨌든 위젯 헤더 파일을 포함시켜야 할 것입니다. typedef (좋은 생각 인 imo)을 Widget.h에 넣으면 나에게 100 % 의미가 있습니다.

+0

어쩌면 저는 -하지만이 해결책은 _interface_의 구현자를 어떻게 _implementation_의 클라이언트가'위젯 '을 가리키고 싶어하는지 짐작할 수 있습니다. – Marc

+0

@Marc - 'shared_ptr'의 사용은 일반적으로 클래스의 의미에 의해 결정됩니다. '보통'의 경우는 객체 복사본을 사용하는 것입니다. 그러므로'위젯 (widget) '은'shared_ptr'을 사용하여 최적으로 관리되는 것이 인터페이스의 일부가되어야한다고 말하고 싶습니다. 물론 대체 사용법을 막지는 못합니다. –

+0

흥미 롭습니다. 'typedef '를'Widget.h'에'편의상'(즉'위젯'에 특별한 의미가없는 상황에서) 두는 것에 동의하지 않으시겠습니까? – Marc

6

또한, 위젯의 선언시 부스트 :: shared_ptr의를 형식 정의를 할 수 있도록 감각을하지 않는 것 자체-우리는 클라이언트가 위젯 인터페이스의 활용 방법의 기대와 위젯의 선언을 혼합 것으로 보인다.

모든

첫째, 이것은 전혀 잘못된되지 않습니다 - 결국, 클라이언트 것 (수) 인터페이스 를 사용하는 방법의 수단은 인터페이스 자체의 부분이다; 가비지 컬렉팅되지 않는 C++의 경우 객체의 메모리 관리는 인터페이스에서 매우 중요한 부분입니다.

그래서 두 가지 경우가 있습니다. 하나의 경우, Widget은 공유 포인터를 통해 사용될 것이라고 예상합니다. 이것은 예를 들어. 위젯에서 가져온 자식 위젯은 shared_ptr으로 반환되고, 생성 된 모든 위젯은 shared_ptr 등으로 반환됩니다. Widget과 동일한 헤더에 WidgetPtr을 typedef하는 것은 전적으로 합법적입니다.

두 번째 경우에는 Widget이 예를 들어 관리 될 것으로 예상됩니다. 보통 newdelete. 클라이언트는 특별한 경우에 shared_ptr을 사용할 수 있지만 예를 들어 아무 것도 말하지 않습니다. 프린터 대화 루틴에서는 대신 auto_ptr을 사용할 수 없습니다. 클라이언트는 준비 할 필요가 wptrshared_ptr,

shared_ptr<Widget> w2(wptr->firstChild()->parent()); 

재해로 연결 라인을 경우.

귀하의 질문은 후자가 귀하의 사례임을 나타내는 것 같습니다. 그래서 IMHO, 당신이 한 것은 괜찮습니다. 클라이언트는 다른 클라이언트에 영향을 미치지 않는 한 Widget 오브젝트를 관리하는 수단을 선택할 수 있습니다.

+0

예, 저의 스케치는 후자의 경우를 대단히 제안했습니다. 의견을 보내 주셔서 감사합니다. – Marc

1

저는 C++ 코드를 라이브러리로 구조화하는 데 사용되었습니다. 라이브러리에는 클라이언트 사용을위한 일련의 헤더가 있으며, 모두 include/LibraryName 디렉토리에 있습니다. 또한이 디렉토리 안에는 Fwd.h이라는 헤더가 하나 있으며 모든 클래스의 전달 선언과 포인터 typedef가 있습니다.

또한 각 공개 헤더에는 Fwd.h이 포함되어 있으므로 헤더를 포함하면 자동으로 모든 전달 선언 및 포인터 typedef가 제공됩니다. 이것은 실제로 잘 작동했습니다.

비록 모든 클래스가 shared_ptr에 배치해야하는 것은 아닙니다. 동적으로 생성 될 것으로 예상되는 유형의 포인터 typedef 만 작성하고이 경우에는 팩토리를 제공합니다. 이는 클라이언트 코드에 인터페이스 유형만을 제공하고 라이브러리의 src 디렉토리에 구체화 된 구현을 숨기는 이점이 있습니다. 구체적으로 당신이 조언을 구했던 것은 아니지만 이것이 나의 방법에 대한 완전한 그림을줍니다. 마지막으로, Fwd.h 및 기타 모든 공용 헤더가 포함 된 LibraryName.h이라는 편리한 헤더를 제공 할 수도 있습니다.

행운을 빈다.

0

두 번째 부분은 첫째 : 네임 스페이스를 사용, 예 :

namespace WidgetStuff { 
    class Widget { .. 
    typedef shared_ptr<Widget> WidgetPtr; 
    .. 

당신이 그것을 분할하려는 경우 :

namespace WidgetStuff { 
    class Widget { ... 
} 
... 
namespace WidgetStuff { 
    typedef ... 

라이브러리 저자있어, 당신에게 자신의 네임 스페이스, 그래서 아무도 그것을 침략해서는 안됩니다. 당신은 당신이 할 수있는 선택하는 경우

그리고 지금의 일이 너무 대답한다 :

#include <widget.h> 
#include <widget_utils.h> 

로 위의 공간을 분할하여. 효과는 네임 스페이스에 침입해서는 안되는 지 여부와 관계없이 유틸리티를 사용하지 않아도되므로 네임 스페이스에없는 한 WidgetPtr을 다른 것으로 만들 수 있습니다.

1

일반적으로이 방법을 사용하여 타이핑을 쉽게하고 클래스에 대한 일반 공유 포인터 인터페이스를 만듭니다. 메모는 C++ 0x입니다.

#include <iostream> 
#include <memory> 

template <class T> 
struct SharedVirtual 
{ 
    typedef std::shared_ptr<T> VPtr; 
}; 

template <class T> 
struct Shared 
{ 
    typedef std::shared_ptr<T> Ptr; 

    template <class... P> 
    static Ptr ptr(P&&... args) 
    { 
     return std::make_shared<T>(std::forward<P>(args)...); 
    } 
}; 

class Foo : public SharedVirtual<Foo> 
{ 
    public: 
     virtual void foo() const = 0; 
}; 

class Test : public Foo, public Shared<Test> 
{ 
    public: 
     void foo() const { std::cout << "Hai u!" << std::endl; } 
}; 

void print(const Foo::VPtr& ptr) 
{ 
    ptr->foo(); 
} 

int main() 
{ 
    auto ptr = Test::ptr(); 
    print(ptr); 
} 
2

내 접근 나는 const_ptr 버전을 발견

class Type 
{ 
    public: 
     typedef shared_ptr<Type>  ptr; 
     typedef shared_ptr<const Type> const_ptr; 
}; 

(그것이 내가 그것을 어떻게해서, 언더 유형을 사용) 무척 유용합니다.

+0

바로 그 순간에 제가 생각하고있는 것입니다. 왜냐하면 상수 인스턴스 **와 ** 변경 가능한 인스턴스에 대한 스마트 포인터가 필요하기 때문입니다. –

관련 문제