有没有办法在不修改 Base Class 的情况下防止 Derived Class 中的内存泄漏?
Is there a way to prevent Memory Leaks in a Derived Class without modifying the Base Class?
所以我有一个基础 class 看起来像这样:
class base {
public:
base() {
std::cout << "We created a base!" << std::endl;
}
~base() {
std::cout << "We destroyed a base!" << std::endl;
}
};
我有一个派生的 class 看起来像这样:
class leaks_memory : public base {
public:
leaks_memory(size_t count) :
memory(new int[count]), size_of_memory(count)
{
announce();
}
leaks_memory(const leaks_memory & lm) :
leaks_memory(lm.size_of_memory)
{
std::copy(lm.memory, lm.memory + size_of_memory, memory);
}
void swap(leaks_memory & lm) noexcept {
std::swap(lm.memory, memory);
std::swap(lm.size_of_memory, size_of_memory);
}
leaks_memory(leaks_memory && lm) {
swap(lm);
}
leaks_memory & operator=(leaks_memory lm) {
swap(lm);
return *this;
}
~leaks_memory() {
delete[] memory;
dennounce();
}
int & operator[](size_t index) {
return memory[index];
}
const int & operator[](size_t index) const {
return memory[index];
}
private:
int * memory;
size_t size_of_memory;
void announce() const noexcept {
std::cout << "We created a Leaks Memory!" << std::endl;
}
void dennounce() const noexcept {
std::cout << "We destroyed a Leaks Memory!" << std::endl;
}
};
现在,这些都不是问题,直到我编写如下所示的代码:
int main() {
std::unique_ptr<base> base_ptr;
std::atomic_bool done = false;
std::thread input_thread{ [&done] {
std::getline(std::cin, std::string());
done = true;
} };
while (!done) {
base_ptr = std::make_unique<leaks_memory>(20'000);
}
input_thread.join();
return 0;
}
此代码在循环的每次迭代中泄漏 20kb,因为 leaks_memory
析构函数从未被调用!
现在,很明显,我可以通过编辑 base
:
来解决这个问题
virtual ~base() {
std::cout << "We destroyed a base!" << std::endl;
}
事实上,如果我在进行此更改后 运行 相同的代码,我将不再有此内存泄漏。
但是,如果我处于无法编辑 base
class 的情况怎么办?有没有办法在不完全改变执行代码的设计的情况下防止内存泄漏?
C++11 智能指针具有自定义删除器,这在一定程度上放宽了在每个层次结构的根部具有虚拟析构元的要求。
遗憾的是这个功能不好用,因为删除器的类型是shared_ptr和unique_ptr的模板参数。所以为了隐藏最终对象的类型,需要一点类型擦除:
void derived_deleter(base* p) { delete static_cast<derived*>(p); }
std::unique_ptr<base, decltype(&derived_deleter)> base_ptr (new derived, derived_deleter);
好像没办法用std::make_unique.
另一种选择,如果您可以使用 const
参考,则可以使用 "most important const"
下面将创建对基类的引用,但会调用派生的析构函数。
leaks_memory factory()
{
return leaks_memory(20'000);
}
int main()
{
//std::unique_ptr<base> base_ptr;
std::atomic_bool done = false;
std::thread input_thread{[&done] {
std::getline(std::cin, std::string());
done = true;
}};
while (!done) {
//base_ptr = std::make_unique<leaks_memory>(20'000);
const base& base_const_ref = factory();
}
input_thread.join();
return 0;
}
所以我有一个基础 class 看起来像这样:
class base {
public:
base() {
std::cout << "We created a base!" << std::endl;
}
~base() {
std::cout << "We destroyed a base!" << std::endl;
}
};
我有一个派生的 class 看起来像这样:
class leaks_memory : public base {
public:
leaks_memory(size_t count) :
memory(new int[count]), size_of_memory(count)
{
announce();
}
leaks_memory(const leaks_memory & lm) :
leaks_memory(lm.size_of_memory)
{
std::copy(lm.memory, lm.memory + size_of_memory, memory);
}
void swap(leaks_memory & lm) noexcept {
std::swap(lm.memory, memory);
std::swap(lm.size_of_memory, size_of_memory);
}
leaks_memory(leaks_memory && lm) {
swap(lm);
}
leaks_memory & operator=(leaks_memory lm) {
swap(lm);
return *this;
}
~leaks_memory() {
delete[] memory;
dennounce();
}
int & operator[](size_t index) {
return memory[index];
}
const int & operator[](size_t index) const {
return memory[index];
}
private:
int * memory;
size_t size_of_memory;
void announce() const noexcept {
std::cout << "We created a Leaks Memory!" << std::endl;
}
void dennounce() const noexcept {
std::cout << "We destroyed a Leaks Memory!" << std::endl;
}
};
现在,这些都不是问题,直到我编写如下所示的代码:
int main() {
std::unique_ptr<base> base_ptr;
std::atomic_bool done = false;
std::thread input_thread{ [&done] {
std::getline(std::cin, std::string());
done = true;
} };
while (!done) {
base_ptr = std::make_unique<leaks_memory>(20'000);
}
input_thread.join();
return 0;
}
此代码在循环的每次迭代中泄漏 20kb,因为 leaks_memory
析构函数从未被调用!
现在,很明显,我可以通过编辑 base
:
virtual ~base() {
std::cout << "We destroyed a base!" << std::endl;
}
事实上,如果我在进行此更改后 运行 相同的代码,我将不再有此内存泄漏。
但是,如果我处于无法编辑 base
class 的情况怎么办?有没有办法在不完全改变执行代码的设计的情况下防止内存泄漏?
C++11 智能指针具有自定义删除器,这在一定程度上放宽了在每个层次结构的根部具有虚拟析构元的要求。
遗憾的是这个功能不好用,因为删除器的类型是shared_ptr和unique_ptr的模板参数。所以为了隐藏最终对象的类型,需要一点类型擦除:
void derived_deleter(base* p) { delete static_cast<derived*>(p); }
std::unique_ptr<base, decltype(&derived_deleter)> base_ptr (new derived, derived_deleter);
好像没办法用std::make_unique.
另一种选择,如果您可以使用 const
参考,则可以使用 "most important const"
下面将创建对基类的引用,但会调用派生的析构函数。
leaks_memory factory()
{
return leaks_memory(20'000);
}
int main()
{
//std::unique_ptr<base> base_ptr;
std::atomic_bool done = false;
std::thread input_thread{[&done] {
std::getline(std::cin, std::string());
done = true;
}};
while (!done) {
//base_ptr = std::make_unique<leaks_memory>(20'000);
const base& base_const_ref = factory();
}
input_thread.join();
return 0;
}