如何在此方案中管理内存

时间:2014-03-26 19:41:08

标签: c++ memory-management smart-pointers

我目前正致力于实现与此类似的功能 (http://molecularmusings.wordpress.com/2011/06/27/config-values/) 使用模板系统时,我不必为我想要支持的所有类型创建一个类。现在这个类本身工作正常,但是如果我从文件中读取配置值并将它们保存到列表中,我就无法弄清楚如何管理内存。

这是我的ConfigSetting类:

#pragma once
template <typename T>
class ConfigSetting {
public:
    static ConfigSetting* head;
    static ConfigSetting* tail;
public:
    ConfigSetting(const std::string& name, const std::string& synopsis, T initValue) : m_name(name), m_synopsis(synopsis), m_value(initValue)
    {
        this->addToList();
    }

    // Special constructor for int ranges
    ConfigSetting(const std::string& name, const std::string& synopsis, T initValue, T minValue, T maxValue) : m_name(name), m_synopsis(synopsis), m_value(initValue), m_min(minValue), m_max(maxValue)
    {
        this->addToList();
    }

    ConfigSetting& operator=(T value)
    {
        this->m_value = value;
        return *this;
    }

    inline operator T(void) const
    {
        return m_value;
    }


    static ConfigSetting* findSetting(const std::string& name)
    {
        if (head) {
            ConfigSetting* temp = head;
            while (temp != nullptr) {
                if (temp->m_name == name) {
                    return temp;
                }
                temp = temp->m_next;
            }
        }
        return nullptr;
    }

private:
    void addToList(void)
    {
        if (head) {
            tail->m_next = this;
            tail = this;
        }
        else {
            head = this;
            tail = this;    
        }
    }

    ConfigSetting* m_next;
    const std::string m_name;
    const std::string m_synopsis;
    T m_value;
    T m_min;
    T m_max;
};

template<class T> ConfigSetting<T>* ConfigSetting<T>::head = nullptr;
template<class T> ConfigSetting<T>* ConfigSetting<T>::tail = nullptr;

我正在使用它(来自另一个名为ConfigReader的类):

ConfigSetting<std::string>* cf = new ConfigSetting<std::string>(key, synopsis, value);

现在我的问题是:在这种情况下管理内存的最佳方法是什么?由于列表是静态的,因此一旦析构函数被调用,我就无法通过列表删除所有内容。我可以像这样使用shared_ptr

shared_ptr<ConfigSetting<std::string>> sp(new ConfigSetting<std::string>(key, synopsis, value));

或其他类型的智能指针?也许有更优雅的解决方案,我没有想到。

1 个答案:

答案 0 :(得分:1)

据我所知,隐式析构函数中没有任何内容可以必须被调用以确保正常运行。如果这是真的,您可以忘记清理列表。尝试这样做只会增加程序的运行时间,绝对没有任何好处。只要让内核完成它的工作,它就不会泄漏任何内存页面,只是因为你不能打扰清理静态数据。


但是,如果你有一个非常重要的析构函数,包括诸如刷新文件或向其他进程发送消息等重要操作,那么你必须使用析构函数。我不是在谈论这里的普通C ++析构函数,而是在main()退出之后由运行时执行的特殊声明的函数。

使用gcc,您可以声明这样的析构函数:

void foo() __attribute__((destructor));

void foo() {
    //Do vitally important cleanup here.
}

由于链接器负责指示运行时调用析构函数,因此您不必对这些函数进行任何调用,实际上可以使用文件本地可见性声明它们。


现在,你问“我不应该在某个地方delete这个指针?”是的,你假设删除它。您应该使用delete为使用new创建的每个对象调用delete,原因有两个:

  1. 将对象持有的内存返回给运行时,以便您的进程可以将内存重用于其他目的。如果您未能定期创建delete个对象,则进程的内存占用量将无限增加,直到内核进入并关闭您的进程。

  2. 运行对象的析构函数,这经常导致在其他不再需要的对象上调用new。在大多数情况下,这只会根据1回馈更多内存,这似乎是你的情况。不过,它可能会做更重要的操作。

  3. 由于有问题的对象必须存活到你的进程生命周期的最后(毕竟它们是静态数据),你不可能重用它们的内存。但是,内核高于为您提供deletenew关键字的运行时级别。内核是您的小型流程世界的创建者,其中delete和{{1}}关键字恰好存在。内核不关心运行时认为使用/未使用的虚拟地址空间的哪些部分。当进程退出时,内核将简单地删除整个虚拟地址空间,并且内存的已使用/未使用状态将消失为虚无。