有没有办法在不修改基类的情况下防止派生类中的内存泄漏?

时间:2016-05-03 16:05:34

标签: c++ inheritance memory-management memory-leaks virtual-method

所以我有一个基类看起来像这样:

class base {
public:
    base() {
        std::cout << "We created a base!" << std::endl;
    }

    ~base() {
        std::cout << "We destroyed a base!" << std::endl;
    }
};

我有一个派生类看起来像这样:

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课程的情况怎么办?有没有办法在不完全改变执行代码设计的情况下防止内存泄漏?

2 个答案:

答案 0 :(得分:2)

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。

答案 1 :(得分:0)

如果您可以使用const引用,则另一个选项可能是使用"most important const"

以下内容将创建对base的引用,但会调用派生的析构函数。

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;
}