초기화 방법을 피하십시오


12

이 클래스에는 클래스와 초기화 메소드가있는 기존 코드가 있습니다. 일단 클래스의 객체가 생성되면 initialize를 호출해야합니다.

initialize 메소드가 존재하는 이유 전역 범위를 갖기 위해 오브젝트가 조기에 작성된 후 initialize 메소드가 종속 된 dll을로드 한 후 나중에 호출됩니다.

초기화 관련 문제 이제 클래스에는이 bool isInitialized가 있으며,이 bool isInitialized는 진행하기 전에 모든 메소드에서 확인해야하며 초기화되지 않은 경우 오류를 리턴합니다. 간단히 말해, 그것은 큰 고통입니다.

하나의 가능한 솔루션 생성자에서 초기화하십시오. 전역 범위의 개체에 대한 포인터 만 있습니다. dll이로드 된 후 실제 객체를 만듭니다.

위 솔루션의 문제이 클래스의 객체를 만드는 사람은 dll이로드 된 후에 만 ​​생성해야하며 그렇지 않으면 실패 할 것입니다.

이것이 허용됩니까?


OpenGL 컨텍스트가 존재하기 전에 인스턴스화해야하는 OpenGL 관련 객체를 생성 할 때도 이와 동일한 문제가 발생했지만 콜리스트, 텍스처 등과 같은 OpenGL 종속 객체를 보유해야합니다.

3
어리석은 질문 # 1 : 왜 객체 생성자가 DLL이 아직로드되지 않은 경우 DLL을로드 할 수 없습니까?
John R. Strohm 2016

1
오래된 질문을 부활을 드려 죄송 경우 사람이, 2017 년에이를 읽고 사용 call_onceC ++ 11을 . 아직 C ++ 11에 포함되지 않은 프로젝트는 C ++ 11에서 call_once가 어떻게 구현되는지 연구하고 (어떻게 해결하고 어떤 문제에 초점을 맞추는 지), C ++의 (맛있는) 풍미로 다시 구현해야합니다. 상태를 정적으로 초기화해야하는 멀티 스레드 안전 동기화 프리미티브가 필요합니다 (상수 값으로). C ++ 11 이전의 컴파일러에는 만족해야 할 다른 특성이있을 수 있습니다.
rwong

답변:


7

가상 프록시 작업처럼 들립니다.

해당 객체에 대한 참조를 포함하는 가상 프록시를 만들 수 있습니다. DLL이로드되지 않은 경우 프록시는 클라이언트에게 특정 기본 동작을 제공 할 수 있습니다. 일단 DLL이로드되면 프록시는 모든 요청을 실제 주제로 전달합니다.

가상 프록시는 DLL 초기화 확인을 담당하며이를 기반으로 요청이 실제 주제에 위임되어야하는지 여부를 결정합니다.

위키 백과의 프록시 패턴

이 아이디어는 어떻습니까?


당신은 여기서 많이 해결하지 않습니다. 실제 객체에 추가 된 모든 메소드에 대해 해당 메소드를 프록시에 추가해야합니다. 아니?

이것은 init를 호출하는 것을 기억하는 문제를 피합니다. 함수에 있지만 프록시의 모든 함수는 여전히 .dll 이로 드되었는지 확인해야합니다.

1
@Sriram은 프록시를 사용하여 DLL 검사와 관련된 유지 관리를 단일 클래스 인 프록시로 제한했습니다. 클래스의 클라이언트는 DLL 검사에 대해 전혀 알 필요조차 없습니다. 대부분의 메소드가 위임을 수행하므로 프록시의 실제 주제 모두에서 인터페이스를 구현 해야하는 데 큰 문제가 없습니다. 즉, DLL이로드되었다고 확신 할 때까지 실제 주제를 작성하지 못하게 할 수 있으며 매번 DLL 상태를 확인할 필요가 없습니다.

@edalorzo : 아이디어는 좋지만 여기서 문제는 이미 프록시에 대해 이야기하고 있으며 OP는 프록시의 각 방법을 확인해야한다는 것에 대해 불평하고 있습니다.
Matthieu M.

4

DLL이 아직로드되지 않은 경우 유용한 정보가 없습니다. 개체는 오류 만 생성합니다. 치명적인 오류입니까? 오류는 어떻게 처리됩니까?

테스트 방법이 완제품에서이 오류가 발생하지 않는지 확인합니까?

건축 디자인이 아니라 테스트 작업처럼 들립니다. assert결코 발생 하지 않는 오류를 반환하지 마십시오 .

현재 오류를 잡아서 무시하는 클래스의 클라이언트를 수정하여 처음부터 시도하지 않도록하십시오.

다중 스레드 패턴은 DLL을로드 한 후 공유 조건 변수를 설정하고 DLL이로드 될 때까지 객체의 생성자가 대기하고 다른 스레드를 차단하게하는 것일 수 있습니다.


DLL이 올바르게 초기화되지 않은 경우 문제의 객체를 만들 때 예외를 던지는 데 아무런 문제가 없다고 생각합니다. 그런 다음 클라이언트 코드는이 예외 만 처리하면되며 테스트를 통해 예외가 올바르게 처리되는지 확인해야합니다.

2

첫 번째 : 상태가 변경되지 않는 한 전역 개체를 해충으로 피하십시오 (구성).

어떤 이유에서든 문제가 발생하면 도움이 될만한 몇 가지 디자인이 있습니다.

나는 두 가지 아이디어를 생각해 냈습니다.

  1. Facade를 사용하여 DLL을로드하십시오. 오브젝트는 Facade를 통해서만 액세스 할 수 있으며, Facade는 생성시 DLL을로드하고 동시에 오브젝트를 인스턴스화합니다.

  2. 프록시를 사용하지만 똑똑한 종류를 사용하십시오.)

@edalorzo 의 대답이 당신을 두려워 할지도 모른다고 두려워하기 때문에 두 번째 요점을 자세히 설명하겠습니다 .

// Private
static Object& GetObjectImpl() { static Object O; return O; }

// Public
static Object& GetObject() {
  Object& o = GetObjectImpl();
  assert(o.isInitialized() && "Object not initialized yet!");
  return o;
}

이제 한 번만 확인하면됩니다.

이것은 일종의 스마트 포인터를 통해 수행 할 수도 있습니다.

Pointer<Object> o;

여기에서는 포인터를위한 공간 만 예약하고, 처음에는 null이며, DLL이로드 될 때만 실제로 객체를 할당합니다. 이전의 모든 액세스는 예외를 발생 시키거나 (NullException : p?) 프로그램을 완전히 종료해야합니다.


1

이것은 까다로운 질문입니다. 아키텍처가 문제에 도움이 될 수 있다고 생각합니다.

증거에 따르면 프로그램이로드 될 때 .dll 이로 드되지 않은 것처럼 들립니다. 플러그인처럼 들립니다.

염두에 두어야 할 것은 .dll을 초기화해야한다는 것입니다. 프로그래머는 어쨌든 객체가 안정적으로 돌아 오지 않을 것이라고 가정해야합니다. 이 ( bool isObjectLoaded() { return isInitialized; })를 활용할 수도 있지만 수표에 대한 더 많은 버그 보고서를 얻을 수 있습니다.

나는 싱글 톤을 생각하고 있었다.

싱글 톤을 호출하면 올바른 객체를 검색 할 수 있으면 올바른 객체를 반환해야합니다. 올바른 객체를 반환 할 수 없으면 오류 값 / nullptr / 빈 기본 객체가 표시됩니다. 그러나 객체가 당신에게 죽을 수 있다면 작동하지 않습니다.

또한 객체의 여러 인스턴스가 필요한 경우 팩토리와 같은 것을 대신 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.