>source

저는 C++로 라이브러리를 만들고 있으며 원할 때마다 일부 개체를 릴리스하고 싶습니다. 원시 포인터를 사용하면 포인터가 더 이상 유효하지 않다는 것을 사용자에게 알릴 수 없었습니다.공유_ptr사용자가 자신의 개체를 가지고 있으면 개체를 해제할 수 없습니다.공유_ptr그것에. 그래서 나는 내 자신의 스마트 포인터(ish) 클래스를 작성하기로 결정했습니다. 내 목표는 참조 횟수를 계산하고 참조 횟수가 0에 도달하면 메모리를 해제하는 클래스를 만드는 것이었습니다. 이는 다음과 유사합니다.공유_ptr그러나파괴하다메모리를 해제하는 메소드. 또한 사용자는 메모리가 아직 유효한(또는 해제된) 여부를 요청할 수 있습니다.

포인터 래퍼클래스는 원시 포인터와 참조 횟수를 포함합니다. 앞서 말했듯이 참조 횟수가 0에 도달하거나 사용자가 호출하면 원시 포인터를 해제합니다.파괴하다방법.

template

하지만포인터 래퍼클래스는 내부 사용을 위한 것이며 라이브러리의 사용자는 항상ptr사례. 사용자는 복사할 수 있습니다.ptr객체를 제외한 모든 복사ptr사물'pw변수는 같은 것을 가리킬 것입니다포인터 래퍼. 이렇게 하면 내가 하나를 호출하면ptr사물'파괴하다방법, 다른 모든ptr사물'is_valid메서드가 반환됩니다거짓. 따라서 라이브러리가 객체를 릴리스하면 사용자는 다음을 호출하면 이를 알 수 있습니다.is_valid사용 전 방법.

template class ptr {
private:
    pointer_wrapper* pw;
public:
    ptr(T* const raw_pointer) { pw= new pointer_wrapper(raw_pointer); }
    ptr(pointer_wrapper* const pw): pw(pw) { pw->increase_reference_count(); }
    ptr(const ptr&
 other_ptr) {
        pw= other_ptr.pw;
        pw->increase_reference_count();
    }
    ptr&
 operator=(const ptr&
 other_ptr) {
        pw->decrease_reference_count();
        pw= other_ptr.pw;
        pw->increase_reference_count();
        return *this;
    }
    T* operator->() const { return pw->get_raw_pointer(); }
    int32_t get_reference_count() const { return pw->get_reference_count(); }
    bool is_valid() const { return pw->get_raw_pointer() != nullptr; }
    //the problem is probably here
    template ptr convert() const { return ptr(reinterpret_cast*>(pw)); }
    void destroy() { pw->destroy(); }
    ~ptr() { pw->decrease_reference_count(); }
};

일반적인 패턴은 순수 가상 메서드만 있는 내보낸 인터페이스와 같은 클래스가 있고 인터페이스와 같은 클래스에서 상속하는 구현 클래스(내보내지 않고 dll에 숨겨져 있음)가 있다는 것입니다.

static ptr create() { return ptr(new wm_glfw_window_system()); }

이것은 잘 작동합니다.전환하다방법. 변환된 메서드를 호출하면ptr개체, 다음과 같은 오류가 발생합니다.

example_1.exe의 0x0000000000000000에서 예외가 발생했습니다. 0xC0000005: 액세스 위반 실행 위치 0x0000000000000000.

ptr(new wm_glfw_window_system())->create_window(...); //works fine
ptr(new wm_glfw_window_system())->create_window(...); //works fine
ptr(new wm_glfw_window_system()).convert(new wm_glfw_window_system()).convert()->create_window(...); //error

그래서 나는 그것에 약간의 문제가 있다고 생각합니다.전환하다방법과재해석_캐스트. 하지만 내 말이 맞다면 수업 때문에 다른 캐스트를 사용할 수 없습니다.ptr< window_system>그리고ptr< wm_glfw_window_system> 에도 불구하고 관련이 없다.창 시스템그리고wm_glfw_window_system수업이 관련되어 있습니다.

제 질문은 다음과 같습니다.

  • 내 목표를 보관하는 더 좋은 방법이 있습니까(예: 적절한 포인터 유형이 있는 라이브러리)?
  • 내 수업이 의미가 있나요?
  • 내 글을 어떻게전환하다제대로 작동하는 방법(다운캐스팅을 지원해야 함)?

"다른 캐스트를 사용할 수 없습니다." → reinterpret_cast도 사용할 수 없습니다. 유일한 차이점은 컴파일러가 이를 허용한다는 것입니다. 당신의 프로그램은 여전히 ​​틀릴 것이고 충돌이나 다른 흥미로운 결과가 예상됩니다.

spectras2021-09-23 12:33:10

code B가 포인터를 파괴할 때 code A가 포인터를 사용하는 도중에 있으면 어떻게 됩니까?

Yakk - Adam Nevraumont2021-09-23 12:33:10

내가 이해하는 한 래퍼가 아닌 내부 포인터 유형에 대해 dynamic_cast를 수행해야 합니다. C++에서 컴파일러는 static_cast 또는 dynamic_cast를 수행할 때 포인터를 조정한다는 것을 알아야 합니다. reinterpret_cast는 거의 임시 유형으로 변환한 다음 정확한 원래 유형으로 다시 변환하는 데만 사용할 수 있으며 주로 사용자 정의 포인터를 전달할 수 있는 API로 작업하는 데 유용합니다... 특정 컴파일러의 경우 다른 용도가 있을 수 있습니다. reinterpret_cast의하지만 이식 가능하지 않을 수 있습니다.

Phil19702021-09-23 12:33:10

사용자 지정 삭제 프로그램 및 (std::shared_ptr 포함) /또는 std::weak_ptr이 원하는 것일 수 있습니다.

Phil19702021-09-23 12:33:10

spectras, Phil1970: 좋습니다. 따라서 reinterpret_cast를 사용하는 것은 좋은 생각이 아닙니다. Yakk -Adam Nevraumont: 제 경우에는 실제로 일어날 수 없습니다. Phil1970: 하지만 제 말이 맞다면 이 삭제자는 마지막 경우에만 호출됩니다. shared_ptr이 파괴됨

racz162021-09-22 19:29:49
  • 답변 # 1

    캐스팅을 다시 해석하지 마세요.

    포인터 래퍼에 대한 단일 포인터를 개체에 대한 포인터와 참조 카운팅 도우미로 교체합니다.

    동일한 참조 카운터를 유지하는 개체에 대한 포인터의 정적, 암시적 및 동적 캐스트를 지원합니다.

    (이는 대략적으로 shared_ptr이 작동하는 방식입니다).

    귀하의 code가 정의되지 않은 동작을 나타내는 것 외에 문제는 기본 및 파생에 대한 포인터가 동일한 값을 가질 필요가 없다는 것입니다.

  • 답변 # 2

    캐스팅을 다시 해석하지 마세요.

    포인터 래퍼에 대한 단일 포인터를 개체에 대한 포인터와 참조 카운팅 도우미로 교체합니다.

    동일한 참조 카운터를 유지하는 개체에 대한 포인터의 정적, 암시적 및 동적 캐스트를 지원합니다.

    (이는 대략적으로 shared_ptr이 작동하는 방식입니다).

    귀하의 code가 정의되지 않은 동작을 나타내는 것 외에 문제는 기본 및 파생에 대한 포인터가 동일한 값을 가질 필요가 없다는 것입니다.

  • 답변 # 3

    함께공유_ptr사용자가 자신의 개체를 가지고 있으면 개체를 해제할 수 없습니다.공유_ptr그것에. 내 목표를 보관하는 더 좋은 방법이 있습니까(예: 적절한 포인터 유형이 있는 라이브러리)?

    줄만 하면 되는 것 같다.표준::weak_ptr사용자에게. 변환 및 저장을 원하지 않는 경우std::shared_ptr, 다음과 같이 클래스로 래핑할 수 있습니다.

    template <class T> class
    pointer_wrapper {
    private:
        std::weak_ptr<T> pointer;
    public:
        pointer_wrapper(std::weak_ptr<T> pointer): pointer(pointer) {}
        template <typename F>    bool do_job(F f) {
            if (auto p= pointer.lock()) {
                f(*p);
                return true;
            }
            return false;
        }
        void destroy() {
            do_job([](auto&amp;
     v){
                //Inform your library to remove the shared_ptr.
                v.release_itself();
            });
        }
    };
    

    좋은 생각이지만 아마도 release_itself 메서드를 구현하는 것이 어려울 수 있으므로 Yakk -Adam Nevraumont의 아이디어를 선호합니다.

    racz162021-09-22 19:34:37
  • 답변 # 4

    함께공유_ptr사용자가 자신의 개체를 가지고 있으면 개체를 해제할 수 없습니다.공유_ptr그것에. 내 목표를 보관하는 더 좋은 방법이 있습니까(예: 적절한 포인터 유형이 있는 라이브러리)?

    줄만 하면 되는 것 같다.표준::weak_ptr사용자에게. 변환 및 저장을 원하지 않는 경우std::shared_ptr, 다음과 같이 클래스로 래핑할 수 있습니다.

    template <class T> class
    pointer_wrapper {
    private:
        std::weak_ptr<T> pointer;
    public:
        pointer_wrapper(std::weak_ptr<T> pointer): pointer(pointer) {}
        template <typename F>    bool do_job(F f) {
            if (auto p= pointer.lock()) {
                f(*p);
                return true;
            }
            return false;
        }
        void destroy() {
            do_job([](auto&amp;
     v){
                //Inform your library to remove the shared_ptr.
                v.release_itself();
            });
        }
    };
    

    좋은 생각이지만 아마도 release_itself 메서드를 구현하는 것이 어려울 수 있으므로 Yakk -Adam Nevraumont의 아이디어를 선호합니다.

    racz162021-09-22 19:34:37
  • 이전 arrays : O(nlog(n))의 최소 다음으로 큰 요소
  • 다음 matlab : simulink의 전달 함수 형식으로 PID 컨트롤러를 구현할 수 없는 이유는 무엇입니까?