Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从构造函数内存泄漏引发异常(句柄包装器c+;+;)_C++_Winapi_Constructor_Memory Leaks_Raii - Fatal编程技术网

C++ 从构造函数内存泄漏引发异常(句柄包装器c+;+;)

C++ 从构造函数内存泄漏引发异常(句柄包装器c+;+;),c++,winapi,constructor,memory-leaks,raii,C++,Winapi,Constructor,Memory Leaks,Raii,我正试图编写一个DriveWriterator类来迭代我计算机中的所有卷 我知道下一个类可能会导致内存泄漏,因为: current_ = std::make_unique<Driver>(paths); current_uu=std::使_唯一(路径); 可以引发异常(出于某种原因…),因此构造将不会完成,因此析构函数将不会被调用,句柄也不会正确关闭 正如我所理解的,一旦我收到句柄,我应该停止构建。 但我如何才能做到这一点? FindFirstVolumeW还为我提供了在构造函数

我正试图编写一个DriveWriterator类来迭代我计算机中的所有卷

我知道下一个类可能会导致内存泄漏,因为:

current_ = std::make_unique<Driver>(paths);
current_uu=std::使_唯一(路径);
可以引发异常(出于某种原因…),因此构造将不会完成,因此析构函数将不会被调用,句柄也不会正确关闭

正如我所理解的,一旦我收到句柄,我应该停止构建。 但我如何才能做到这一点? FindFirstVolumeW还为我提供了在构造函数完成之前需要使用的数据

DriverIterator.hpp:

class DriverIterator final
{
public:
    explicit DriverIterator();
     ~DriverIterator();

private:
    std::unique_ptr<Driver> current_;
    bool is_empty_;
    HANDLE handle_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    HANDLE start_find();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::DriverIterator():
    handle_(start_find())
{}

DriverIterator::~DriverIterator()
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::start_find()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;

    return handle;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code...
}
class DriverIterator final
{
private:
    class FindVolumeHandle final
    {
    public:
        explicit FindVolumeHandle(const HANDLE handle);
        ~FindVolumeHandle() noexcept;

    private:
        HANDLE handle_;

    public:
        HANDLE get_handle() const;

    public:
        FindVolumeHandle(const FindVolumeHandle&) = delete;
        FindVolumeHandle(FindVolumeHandle&&) = delete;
        FindVolumeHandle& operator=(const FindVolumeHandle&) = delete;
        FindVolumeHandle& operator=(FindVolumeHandle&&) = delete;
    };

public:
    explicit DriverIterator();

private:
    std::unique_ptr<FindVolumeHandle> wrapped_handle_;
    std::unique_ptr<Driver> current_;
    bool is_empty_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    void initialize();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::FindVolumeHandle::FindVolumeHandle(const HANDLE handle) :
    handle_(handle)
{}

DriverIterator::FindVolumeHandle::~FindVolumeHandle() noexcept
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::FindVolumeHandle::get_handle() const
{
    return handle_;
}


DriverIterator::DriverIterator()
{
    initialize();
}

void DriverIterator::initialize()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wrapped_handle_ = std::make_unique<FindVolumeHandle>(handle);

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code..
}
类驱动程序最终版
{
公众:
显式驱动编写器();
~DriverIterator();
私人:
std::唯一\u ptr电流\uu;
布尔是空的;
手柄;
公众:
bool是_empty()常量;
驱动程序获取_current()常量;
下一步无效();
私人:
句柄start_find();
公众:
DriverIterator(const DriverIterator&)=delete;
DriverIterator(DriverIterator&&)=删除;
DriverIterator&运算符=(const DriverIterator&)=删除;
DriverIterator&operator=(DriverIterator&&)=删除;
};
DriverIterator.cpp:

class DriverIterator final
{
public:
    explicit DriverIterator();
     ~DriverIterator();

private:
    std::unique_ptr<Driver> current_;
    bool is_empty_;
    HANDLE handle_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    HANDLE start_find();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::DriverIterator():
    handle_(start_find())
{}

DriverIterator::~DriverIterator()
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::start_find()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;

    return handle;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code...
}
class DriverIterator final
{
private:
    class FindVolumeHandle final
    {
    public:
        explicit FindVolumeHandle(const HANDLE handle);
        ~FindVolumeHandle() noexcept;

    private:
        HANDLE handle_;

    public:
        HANDLE get_handle() const;

    public:
        FindVolumeHandle(const FindVolumeHandle&) = delete;
        FindVolumeHandle(FindVolumeHandle&&) = delete;
        FindVolumeHandle& operator=(const FindVolumeHandle&) = delete;
        FindVolumeHandle& operator=(FindVolumeHandle&&) = delete;
    };

public:
    explicit DriverIterator();

private:
    std::unique_ptr<FindVolumeHandle> wrapped_handle_;
    std::unique_ptr<Driver> current_;
    bool is_empty_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    void initialize();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::FindVolumeHandle::FindVolumeHandle(const HANDLE handle) :
    handle_(handle)
{}

DriverIterator::FindVolumeHandle::~FindVolumeHandle() noexcept
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::FindVolumeHandle::get_handle() const
{
    return handle_;
}


DriverIterator::DriverIterator()
{
    initialize();
}

void DriverIterator::initialize()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wrapped_handle_ = std::make_unique<FindVolumeHandle>(handle);

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code..
}
DriverIterator::DriverIterator():
句柄(开始查找())
{}
DriverIterator::~DriverIterator()
{
尝试
{
FindVolumeClose(手柄);
}
捕获(…)
{
}
}
handledriveriterator::start\u find()
{
静态constexpr uint32最大缓冲区大小=1024;
wchar_t缓冲区[最大缓冲区大小];
HANDLE HANDLE=FindFirstVolumeW(缓冲区,最大缓冲区大小);
if(句柄==无效的句柄值)
{
//抛出异常
}
wchar_t路径[1024];
德沃德·雷斯库;
if(!GetVolumePathNamesforVolumeName(缓冲区、路径、1024和res_大小))
{
//抛出异常
}
当前_u=std::使_唯一(路径);
is_empty_u=false;
返回手柄;
}
bool DriverIterator::is_empty()常量
{
返回为空;
}
驱动程序DriverIterator::get_current()const
{
如果(是否为空)
{
//抛出异常
}
返回*当前值;
}
void DriverIterator::next()
{
//代码。。。
}

好的,所以我创建了一个名为“FindVolumeHandle”的内部类来包装句柄

我可以用更好的方式来做吗

DriverIterator.hpp:

class DriverIterator final
{
public:
    explicit DriverIterator();
     ~DriverIterator();

private:
    std::unique_ptr<Driver> current_;
    bool is_empty_;
    HANDLE handle_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    HANDLE start_find();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::DriverIterator():
    handle_(start_find())
{}

DriverIterator::~DriverIterator()
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::start_find()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;

    return handle;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code...
}
class DriverIterator final
{
private:
    class FindVolumeHandle final
    {
    public:
        explicit FindVolumeHandle(const HANDLE handle);
        ~FindVolumeHandle() noexcept;

    private:
        HANDLE handle_;

    public:
        HANDLE get_handle() const;

    public:
        FindVolumeHandle(const FindVolumeHandle&) = delete;
        FindVolumeHandle(FindVolumeHandle&&) = delete;
        FindVolumeHandle& operator=(const FindVolumeHandle&) = delete;
        FindVolumeHandle& operator=(FindVolumeHandle&&) = delete;
    };

public:
    explicit DriverIterator();

private:
    std::unique_ptr<FindVolumeHandle> wrapped_handle_;
    std::unique_ptr<Driver> current_;
    bool is_empty_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    void initialize();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::FindVolumeHandle::FindVolumeHandle(const HANDLE handle) :
    handle_(handle)
{}

DriverIterator::FindVolumeHandle::~FindVolumeHandle() noexcept
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::FindVolumeHandle::get_handle() const
{
    return handle_;
}


DriverIterator::DriverIterator()
{
    initialize();
}

void DriverIterator::initialize()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wrapped_handle_ = std::make_unique<FindVolumeHandle>(handle);

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code..
}
类驱动程序最终版
{
私人:
类FindVolumeHandle final
{
公众:
显式FindVolumeHandle(常量句柄);
~FindVolumeHandle()noexcept;
私人:
手柄;
公众:
HANDLE get_HANDLE()常量;
公众:
FindVolumeHandle(const FindVolumeHandle&)=删除;
FindVolumeHandle(FindVolumeHandle&&)=删除;
FindVolumeHandle&运算符=(const FindVolumeHandle&)=删除;
FindVolumeHandle&运算符=(FindVolumeHandle&&)=删除;
};
公众:
显式驱动编写器();
私人:
std::唯一的\u ptr包装的\u手柄\uu;
std::唯一\u ptr电流\uu;
布尔是空的;
公众:
bool是_empty()常量;
驱动程序获取_current()常量;
下一步无效();
私人:
void初始化();
公众:
DriverIterator(const DriverIterator&)=delete;
DriverIterator(DriverIterator&&)=删除;
DriverIterator&运算符=(const DriverIterator&)=删除;
DriverIterator&operator=(DriverIterator&&)=删除;
};
DriverIterator.cpp:

class DriverIterator final
{
public:
    explicit DriverIterator();
     ~DriverIterator();

private:
    std::unique_ptr<Driver> current_;
    bool is_empty_;
    HANDLE handle_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    HANDLE start_find();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::DriverIterator():
    handle_(start_find())
{}

DriverIterator::~DriverIterator()
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::start_find()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;

    return handle;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code...
}
class DriverIterator final
{
private:
    class FindVolumeHandle final
    {
    public:
        explicit FindVolumeHandle(const HANDLE handle);
        ~FindVolumeHandle() noexcept;

    private:
        HANDLE handle_;

    public:
        HANDLE get_handle() const;

    public:
        FindVolumeHandle(const FindVolumeHandle&) = delete;
        FindVolumeHandle(FindVolumeHandle&&) = delete;
        FindVolumeHandle& operator=(const FindVolumeHandle&) = delete;
        FindVolumeHandle& operator=(FindVolumeHandle&&) = delete;
    };

public:
    explicit DriverIterator();

private:
    std::unique_ptr<FindVolumeHandle> wrapped_handle_;
    std::unique_ptr<Driver> current_;
    bool is_empty_;

public:
    bool is_empty() const;
    Driver get_current() const;
    void next();

private:
    void initialize();

public:
    DriverIterator(const DriverIterator&) = delete;
    DriverIterator(DriverIterator&&) = delete;
    DriverIterator& operator=(const DriverIterator&) = delete;
    DriverIterator& operator=(DriverIterator&&) = delete;
};
DriverIterator::FindVolumeHandle::FindVolumeHandle(const HANDLE handle) :
    handle_(handle)
{}

DriverIterator::FindVolumeHandle::~FindVolumeHandle() noexcept
{
    try
    {
        FindVolumeClose(handle_);
    }
    catch (...)
    {

    }
}

HANDLE DriverIterator::FindVolumeHandle::get_handle() const
{
    return handle_;
}


DriverIterator::DriverIterator()
{
    initialize();
}

void DriverIterator::initialize()
{
    static constexpr uint32_t MAX_BUFFER_SIZE = 1024;
    wchar_t buffer[MAX_BUFFER_SIZE];

    HANDLE handle = FindFirstVolumeW(buffer, MAX_BUFFER_SIZE);
    if (handle == INVALID_HANDLE_VALUE)
    {
        //throw exception
    }

    wrapped_handle_ = std::make_unique<FindVolumeHandle>(handle);

    wchar_t paths[1024];
    DWORD   res_size;

    if (!GetVolumePathNamesForVolumeNameW(buffer, paths, 1024, &res_size))
    {
        //throw exception
    }

    current_ = std::make_unique<Driver>(paths);

    is_empty_ = false;
}

bool DriverIterator::is_empty() const
{
    return is_empty_;
}

Driver DriverIterator::get_current() const
{
    if (is_empty_)
    {
        //throw exception
    }

    return *current_;
}

void DriverIterator::next()
{
    //code..
}
DriverIterator::FindVolumeHandle::FindVolumeHandle(常量句柄):
手柄(手柄)
{}
DriveWriter::FindVolumeHandle::~FindVolumeHandle()无例外
{
尝试
{
FindVolumeClose(手柄);
}
捕获(…)
{
}
}
HANDLE DriverIterator::FindVolumeHandle::get_HANDLE()常量
{
返回手柄;
}
DriverIterator::DriverIterator()
{
初始化();
}
void DriverIterator::initialize()
{
静态constexpr uint32最大缓冲区大小=1024;
wchar_t缓冲区[最大缓冲区大小];
HANDLE HANDLE=FindFirstVolumeW(缓冲区,最大缓冲区大小);
if(句柄==无效的句柄值)
{
//抛出异常
}
包装的_句柄=标准::使_唯一(句柄);
wchar_t路径[1024];
德沃德·雷斯库;
if(!GetVolumePathNamesforVolumeName(缓冲区、路径、1024和res_大小))
{
//抛出异常
}
当前_u=std::使_唯一(路径);
is_empty_u=false;
}
bool DriverIterator::is_empty()常量
{
返回为空;
}
驱动程序DriverIterator::get_current()const
{
如果(是否为空)
{
//抛出异常
}
返回*当前值;
}
void DriverIterator::next()
{
//代码。。
}

当构造函数生成异常时,不会调用对象析构函数,但会调用已构造成员的析构函数,并释放为该对象分配的内存

< > >,习惯性C++方式是为代码< > HealLe< /Cux>成员定义RAII包装器,它将提供对基础资源的访问并正确地在析构函数中释放它,例如:

template <typename CloseFnT, CloseFnT close_fn>
class UniqueHandle {
public:
    UniqueHandle()
        : handle_(INVALID_HANDLE_VALUE)
    {
    }

    UniqueHandle(HANDLE handle)
        : handle_(handle)
    {
    }

    ~UniqueHandle()
    {
        if (handle_ != INVALID_HANDLE_VALUE) {
            close_fn(handle_);
        }
    }

    UniqueHandle(const UniqueHandle&) = delete;
    UniqueHandle& operator = (const UniqueHandle&) = delete;

    UniqueHandle(UniqueHandle&& other)
        : handle_(INVALID_HANDLE_VALUE)
    {
        std::swap(handle_, other.handle_);
    }

    UniqueHandle& operator = (UniqueHandle&& other)
    {
        std::swap(handle_, other.handle_);
        return *this;
    }

    HANDLE get() const {
        return handle_;
    }

private:
    HANDLE handle_;
};

using UniqueVolumeHandle = UniqueHandle<decltype(&FindVolumeClose), FindVolumeClose>;

例如,在库中实现了这种方法。

您确定共享ptr是正确的方法吗。由于您不允许复制和赋值,因此永远不会共享此指针。我怀疑unique_ptr更适合您的关注,如果驱动程序类编写正确,其析构函数中的异常不应导致任何不良影响或资源泄漏。由于驱动程序是通过一个智能指针构建和维护的,使_共享或使_唯一,所以这里没有潜在的泄漏,除非驱动程序或的用户中存在泄漏DriverIterator@MichaelVeksler你是对的,我应该使用唯一指针而不是共享指针。然而,当我谈到内存泄漏时,我谈论的是句柄(从FindFirstVolumeW接收),该句柄将无法正确关闭,因为DriverIterator的构造函数在构造驱动程序对象时可能会抛出EXCEPTION