문제

나는 C ++ 아마추어입니다. 나는 Win32 API 코드를 작성하고 있으며 핸들과 이상하게 합리적으로 할당 된 객체가 있습니다. 그래서 궁금했습니다. 자원 관리를 더 쉽게 만들 수있는 래퍼 클래스가 있습니까?

예를 들어, 일부 데이터를로드하고 싶을 때 파일을 열었습니다. CreateFile() 그리고 a HANDLE. 내가 끝났을 때 전화해야합니다 CloseHandle() 그 위에. 그러나 합리적으로 복잡한 로딩 기능의 경우 예외는 말할 것도없이 수십 개의 가능한 출구 포인트가있을 것입니다.

그래서 자동으로 호출 할 래퍼 클래스에 핸들을 감싸면 좋을 것입니다. CloseHandle() 일단 실행이 범위를 떠났습니다. 더 나은 - 그것은 약간의 참조 계산을 수행 할 수 있으므로 다른 기능을 안팎으로 전달할 수 있으며 마지막 참조가 왼쪽으로 남아있을 때만 리소스를 해제 할 수 있습니다.

개념은 간단하지만 표준 라이브러리에 그런 것이 있습니까? 나는 Visual Studio 2008을 사용하고 있으며 Boost 또는 Something과 같은 제 3 자 프레임 워크를 첨부하고 싶지 않습니다.

도움이 되었습니까?

해결책

나만의 글을 쓰십시오. 몇 줄의 코드 일뿐입니다. 그저 간단한 작업 일뿐입니다. 그만한 가치가 있습니다 일반적인 재사용 가능한 버전을 제공합니다.

struct FileWrapper {
  FileWrapper(...) : h(CreateFile(...)) {}
  ~FileWrapper() { CloseHandle(h); }

private:
  HANDLE h;
};

일반 버전이 무엇을 해야하는지 생각해보십시오. 어느 함수 쌍 어느 그들에게 논쟁의 수. 그러한 객체를 인스턴스화하면 위의 클래스 정의만큼 많은 코드 줄이 필요할 수 있습니다.

물론, C ++ 0X는 Lambda 표현을 추가하여 균형을 다소 팁을 줄 수 있습니다. 두 개의 Lambda 표현식을 일반 래퍼 클래스로 쉽게 전달할 수 있으므로 C ++ 0X 지원이 발생하면 우리는 ~할 것 같다 부스트 나 무언가에 추가 된 일반적인 RAII 클래스를 참조하십시오.

그러나 지금은 필요할 때마다 자신을 굴리는 것이 더 쉽습니다.

참조 계산을 추가하면 이에 반대 할 것입니다. 참조 계산은 비싸다 (갑자기 손잡이가 동적으로 할당되어야하며 모든 과제마다 참조 카운터를 유지해야한다). 그것은 실로 된 환경에서 미묘한 경주 조건으로 파열되는 지역입니다.

만약 너라면 하다 참조 계산이 필요합니다 boost::shared_ptr<FileWrapper>: 사용자 정의 Ad-Hoc Raii 클래스를 a shared_ptr.

다른 팁

본질적으로, fstream 파일 핸들을위한 좋은 C ++ 래퍼입니다. 그것은 표준의 일부이며, 이는 휴대용, 잘 테스트되었으며 객체 지향적 인 방식으로 확장 가능하다는 것을 의미합니다. 파일 리소스의 경우 훌륭한 개념입니다.

하지만, fstream 일반 핸들, 즉 스레드, 프로세스, 동기화 객체, 메모리 매핑 파일 등이 아닌 파일에만 작동합니다.

이 포장지는 ATL이라고합니다.

손잡이가 이벤트 또는 이와 유사한 경우 사용하십시오. 챈들 수업.

손잡이가 파일 인 경우 Catlfile 파생 파일을 사용하면 CreateFile 및 ReadFile과 같은 API를 감싸십시오.

ATL에는 다른 유용한 포장지가 있습니다. CAtlFileMapping<T> 메모리 매핑 파일에 대한 raii 래퍼입니다. CPath 경로 처리를 위해 Shell32 API를 랩핑합니다.

ATL은 큰 라이브러리이지만 파일, 문자열 및 컬렉션과 같은 낮은 수준의 것들이 분리되어 있습니다. 모든 Win32 앱에서 사용할 수 있습니다. 헤더는 전용이며, 아무것도 연결하거나 MFC 또는 CRT와 같은 추가 DLL을 배포 할 필요가 없습니다. 코드는 Winapi 통화로 컴파일하고 그냥 작동합니다.

그들은 VS2003 또는 2005의 MFC에서 나뉘어졌습니다. 기억하지 못합니다. 즉, Visual Studio 2008은 분명히 그것들을 가지고 있습니다. 그러나 한 가지 경고가 있지만, FR 프리웨어 버전의 VS를 사용하는 경우 2015 년이거나 최신이어야합니다.

다음은 'C/C ++를 통해 Windows'의 Enseerecleanup 코드를 기반으로 한 것입니다.http://www.codeproject.com/kb/cpp/template2003.aspx

MFC에는 몇 가지 적절한 프리미티브가 있습니다 (봐봐 cfile 예를 들어), 그러나 표준 라이브러리는 아닙니다.

Visual C ++ 2008은 피처 팩을 통해 TR1을 지원하며 TR1에는 Shared_ptr가 포함됩니다. 나는 이것을 사용합니다 - 그것은 매우 강력한 스마트 포인터 클래스이며, 당신이 요구하는 자원 관리 유형을 수행하도록 일반화 될 수 있습니다.

TR1은 효과적으로 표준으로 확장됩니다. 나는 그것이 여전히 공식적으로 "사전 표준"이라고 생각하지만 효과적으로 당신은 그것이 잠겨 있다고 생각할 수 있습니다.

표준 라이브러리에는 아무것도 없다고 생각하며 공유 포인터 (부스트에서와 같이)가 사용할 수 있다고 의심합니다 (포인터가 처리하지 않고 포인터가 처리 할 것으로 예상).

다음을 따라 직접 글을 쓰는 것은 어렵지 않아야합니다. 범위 가드 관용구 (및 선택한 경우 템플릿/기능 포인터 등을 사용).

template <typename Traits>
class unique_handle
{
    using pointer = typename Traits::pointer;

    pointer m_value;

    auto close() throw() -> void
    {
        if (*this)
        {
            Traits::close(m_value);
        }
    }

public:

    unique_handle(unique_handle const &) = delete;
    auto operator=(unique_handle const &)->unique_handle & = delete;

    explicit unique_handle(pointer value = Traits::invalid()) throw() :
        m_value{ value }
    {
    }

    unique_handle(unique_handle && other) throw() :
        m_value{ other.release() }
    {
    }

    auto operator=(unique_handle && other) throw() -> unique_handle &
    {
        if (this != &other)
        {
            reset(other.release());
        }

        return *this;
    }

    ~unique_handle() throw()
    {
        close();
    }

    explicit operator bool() const throw()
    {
        return m_value != Traits::invalid();
    }

    auto get() const throw() -> pointer
    {
        return m_value;
    }

    auto get_address_of() throw() -> pointer *
    {
        ASSERT(!*this);
        return &m_value;
    }

    auto release() throw() -> pointer
    {
        auto value = m_value;
        m_value = Traits::invalid();
        return value;
    }

    auto reset(pointer value = Traits::invalid()) throw() -> bool
    {
        if (m_value != value)
        {
            close();
            m_value = value;
        }

        return static_cast<bool>(*this);
    }

    auto swap(unique_handle<Traits> & other) throw() -> void
    {
        std::swap(m_value, other.m_value);
    }
};

template <typename Traits>
auto swap(unique_handle<Traits> & left,
    unique_handle<Traits> & right) throw() -> void
{
    left.swap(right);
}

template <typename Traits>
auto operator==(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() == right.get();
}

template <typename Traits>
auto operator!=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() != right.get();
}

template <typename Traits>
auto operator<(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() < right.get();
}

template <typename Traits>
auto operator>=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() >= right.get();
}

template <typename Traits>
auto operator>(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() > right.get();
}

template <typename Traits>
auto operator<=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() <= right.get();
}

struct null_handle_traits
{
    using pointer = HANDLE;

    static auto invalid() throw() -> pointer
    {
        return nullptr;
    }

    static auto close(pointer value) throw() -> void
    {
        VERIFY(CloseHandle(value));
    }
};

struct invalid_handle_traits
{
    using pointer = HANDLE;

    static auto invalid() throw() -> pointer
    {
        return INVALID_HANDLE_VALUE;
    }

    static auto close(pointer value) throw() -> void
    {
        VERIFY(CloseHandle(value));
    }
};

using null_handle = unique_handle<null_handle_traits>;
using invalid_handle = unique_handle<invalid_handle_traits>;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top