C++ 从构造函数内存泄漏引发异常(句柄包装器c+;+;)
我正试图编写一个DriveWriterator类来迭代我计算机中的所有卷 我知道下一个类可能会导致内存泄漏,因为: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还为我提供了在构造函数
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