2017-11-17 2 views
1

나는 작업중인 알고리즘의 출력을 시각화하는 옵션을 가진 프로그램을 작성하고 있습니다. 이것은 헤더 파일에 정의 된 변수 const bool VISUALIZE_OUTPUT을 변경하여 수행됩니다. 주 파일에서 나는 다음과 같은 패턴을 원합니다 :조건부로 C++ 객체 작성

if(VISUALIZE_OUTPUT) { 
    VisualizerObject vis_object; 
} 
... 
if(VISUALIZE_OUTPUT) { 
    vis_object.initscene(objects_here); 
} 
... 
if(VISUALIZE_OUTPUT) { 
    vis_object.drawScene(objects_here); 
} 

그러나 vis_object가 범위를 벗어나기 때문에 이것은 분명히 컴파일되지 않습니다. 큰 객체이고 코드의 여러 점에서 사용할 수 있어야하기 때문에 조건 이전에 객체를 선언하고 싶지 않습니다. 모든 작업이 완료된 조건문을 하나만 가질 수는 없습니다.

이렇게하는 것이 바람직한 방법은 무엇입니까?

  • 힙에 개체를 선언하고 포인터 (또는 unique_ptr)를 사용하여 개체를 참조하십시오.
  • 힙에있는 객체를 선언하고 변경하지 않으므로 에 대한 참조를 만드시겠습니까?
  • 다른 대안이 있습니까?
+2

** 가장 바깥 쪽 범위에 있어야하는 'VisualizerObject vis_object;'를 사용하면 성능 문제가 ** 측정 되었습니까? – Caleth

+0

나는 당신이 바라는 "종류의 패턴"에 결함이 있다고 생각합니다. 기본적으로 범위를 존중하지 않는 방식으로 조건 적으로 일을 수행하는 방법을 모색하고 있습니다. 따라서 실행 가능한 옵션은'VISUALIZE_OUTPUT'을 전 처리기 매크로로 만들고,'#ifdef VISUALISE_OUTPUT' /'#endif'에서'vis_object'의 정의와 사용법을 모두 감싸는 것입니다. 선처리가 범위를 존중하지 않기 때문에이 기능이 작동합니다. 그러나 전처리 기 술을 사용하는 것은 C++에서 매우 좋은 이유로 인해 권장되지 않습니다. – Peter

답변

1

선언시 이미 존재하는 객체를 참조하고 모든 if(VISUALIZE_OUTPUT)을 포함하는 범위에 있기 때문에 참조를 사용할 수 없습니다. 짧게 요약하자면, 객체는 무조건 생성되어야합니다.

그래서 IMHO 간단한 방법은 힙에 만들고 포인터를 통해 사용하는 것입니다. 완료되면 delete 잊지 마세요. 좋은 점은 포인터가 nullptr으로 초기화 될 수 있으므로 unconditionnaly 삭제 될 수 있습니다.

하지만 가장 좋은 방법은 가장 높은 범위에서 만들어진 객체의 모든 것을 캡슐화하는 것이라고 생각합니다. 이 객체에는 내부적으로 생성하고 사용하는 메소드가 포함되어 실제 vis_object을 파기합니다. 그런 식으로, 당신이 그것을 필요로하지 않으면, 아무 것도 실제로 instanciated 것입니다,하지만 주요 절차는 원시 포인터 처리로 복잡하지 않습니다.

0

나는 Null_object_pattern을 사용 : 마지막으로

struct IVisualizerObject 
{ 
    virtual ~IVisualizerObject() = default; 
    virtual void initscene(Object&) = 0; 
    virtual void drawScene(Object&) = 0; 
    // ... 
}; 

struct NullVisualizerObject : IVisualizerObject 
{ 
    void initscene(Object&) override { /* Empty */ } 
    void drawScene(Object&) override { /* Empty */} 
    // ... 
}; 

struct VisualizerObject : IVisualizerObject 
{ 
    void initscene(Object& o) override { /*Implementation*/} 
    void drawScene(Object& o) override { /*Implementation*/} 
    // ... 
}; 

과 :

std::unique_ptr<IVisualizerObject> vis_object; 
if (VISUALIZE_OUTPUT) { 
    vis_object = std::make_unique<VisualizerObject>(); 
} else { 
    vis_object = std::make_unique<NullVisualizer>(); 
} 

// ... 
vis_object->initscene(objects_here); 

//... 

vis_object->drawScene(objects_here); 
0

내가 몇 가지 옵션을 제공합니다. 모두 장단점이있다.

VisualizerObject을 수정할 수 없다면 주석에서 언급했듯이 전 처리기가 범위를 고려하지 않고 전처리기를 사용하여 효과를 얻을 수 있으며 질문은 구체적으로 개체의 수명을 제어하는 ​​방식으로 시도합니다 범위 경계를 넘는

#ifdef VISUALIZE_OUTPUT 
    VisualizerObject vis_object; 
#endif 

#ifdef VISUALIZE_OUTPUT 
    vis_object.initscene(objects_here); 
#endif 

컴파일러는 #ifdef/#endif에없는 그 vis_object의 사용을 진단하는 것입니다.

물론 큰 비판은 전처리 기의 사용이 C++에서 좋지 않은 것으로 간주된다는 것입니다. 이점은 VisualizerObject 클래스를 수정할 수없는 경우에도 (예 : 제공되는 소스 코드가없는 제 3 자 라이브러리에 있기 때문에) 접근법을 사용할 수 있다는 것입니다.

그러나 이것은 개체 수명 교차 범위 범위의 OP에서 요청한 기능을 가진 유일한 옵션입니다. 그것은 VisualizerObject 클래스를 수정 할 수 있다면

는 두 개의 전문

template<bool visualise> struct VisualizerObject 
{ 
    // implement all member functions required to do nothing and have no members 

    VisualizerObject() {}; 
    void initscene(types_here) {};  
}; 

template<> struct VisualizerObject<true> // heavyweight implementation with lots of members 
{ 
    VisualizerObject(): heavy1(), heavy2() {}; 
    void initscene(types_here) { expensive_operations_here();}; 

    HeavyWeight1 heavy1; 
    HeavyWeight2 heavy2; 
}; 

int main() 
{ 
     VisualizerObject<VISUALIZE_OUTPUT> vis_object; 
     ... 
     vis_object.initscene(objects_here); 
     ... 
     vis_object.drawScene(objects_here); 
} 

(가) 위의 모든 C++ 버전에서 작동과 템플릿합니다. 본질적으로, 아무것도하지 않는 멤버 함수를 사용하여 가벼운 객체를 인스턴스화하거나 중량 버전을 인스턴스화하여 작동합니다.

VisualizerObject을 감싸는 위의 방법을 사용할 수도 있습니다.

template<bool visualise> VisualizerWrapper 
{ 
     // implement all required member functions to do nothing 
     // don't supply any members either 
} 

template<> VisualizerWrapper<true> 
{ 
     VisualizerWrapper() : object() {}; 

     // implement all member functions as forwarders 

    void initscene(types_here) { object.initscene(types_here);}; 

     VisualizerObject object; 
} 

int main() 
{ 
     VisualizerWrapper<VISUALIZE_OUTPUT> vis_object; 
     ... 
     vis_object.initscene(objects_here); 
     ... 
     vis_object.drawScene(objects_here); 
} 

템플리트 접근법 모두의 단점은 유지 - 다른 동일한 서명 기능을 추가 할 필요가 하나 개의 클래스 (템플릿 전문)을 멤버 함수를 추가 할 때. 대규모 팀 설정에서는 테스트/빌드가 대부분 VISUALIZE_OUTPUT 또는 다른 설정으로 이루어 지므로 한 버전을 다른 인터페이스 (다른 인터페이스)에서 쉽게 가져올 수 있습니다. 이러한 문제 (예 : 설정 변경시 실패한 빌드)는 다른 버전의 제품을 제공하기위한 마감일이 부적절한 경우와 같이 불편한시기에 나타날 수 있습니다.

Pedantically, 템플릿 옵션의 다른 단점은

if(VISUALIZE_OUTPUT) 
{ 
    vis_object.initscene(objects_here); 
} 

에 필요하지 않은 if 즉, 원하는 "패턴의 종류"준수 및 범위의 경계를 교차하지 않는 수명을 반대하지 않는다는 것입니다 .