C++ 构造函数和析构函数中的std::vector::clear()

C++ 构造函数和析构函数中的std::vector::clear(),c++,stl,C++,Stl,我多次遇到在构造函数和析构函数中调用std::vector类型的类成员的std::vector::clear()的代码 我不明白为什么需要它: 构造函数-std::vector类型的类成员默认为空,因此无需调用clear() 析构函数-std::vector类型的类成员将作为包含它的对象的标准销毁的一部分被销毁。作为向量销毁的一部分,包含在其中的所有值对象将被销毁(如果它将分配给内存的指针堆起来,则应“手动”删除它们),因此再次无需调用clear() 我错过什么了吗?不,你说得对。除非构造器(或

我多次遇到在构造函数和析构函数中调用std::vector类型的类成员的std::vector::clear()的代码

我不明白为什么需要它:

  • 构造函数-std::vector类型的类成员默认为空,因此无需调用clear()
  • 析构函数-std::vector类型的类成员将作为包含它的对象的标准销毁的一部分被销毁。作为向量销毁的一部分,包含在其中的所有值对象将被销毁(如果它将分配给内存的指针堆起来,则应“手动”删除它们),因此再次无需调用clear()
    我错过什么了吗?

    不,你说得对。除非构造器(或基类的构造器)中有一些额外的业务需要这样做,但可能性非常低

    以后编辑


    在析构函数的例子中,我看到的一个最常见的错误是,有些人认为clear方法也会为指针的向量(vector)调用delete,当然,情况并非如此。我怀疑这是(无害的)巫毒编程,有点像释放指针后将其设置为null,或者在GUI代码中随机调用repaint/revalidate。程序员记得它在过去帮助解决了一些bug,现在不必要地添加了它“以防万一”。谁知道呢,也许会有帮助。伏都教

    从事物的声音来看,编写代码的人是那些错过了某些东西的人。在Cor或Dor中调用Scar()的唯一时间将在一些其他代码的中间。例如,一个ctor可能读入一些数据,对其进行处理,然后读入更多数据。在这种情况下,在读取数据时使用单个容器并每次清除它可能比每次迭代创建一个新容器更快

  • 清除构造函数中stl容器的内容是完全不必要的
  • 在析构函数中清除stl容器的内容是不必要的,除非该容器包含指针。如果指针是使用新建创建的,则仍然需要先删除它。在此之后,仍然不需要清理容器
  • 考虑这一点:

    #define BOOST_TEST_MODULE StlContainers
    #define BOOST_LIB_DIAGNOSTIC
    
    #include <boost/test/unit_test.hpp>
    #include <boost/assign.hpp>
    #include <boost/assign/list_of.hpp>
    #include <boost/assign/std/vector.hpp>
    
    #include <vector>
    
    using namespace boost::assign;
    using namespace std;
    
    const vector<int> my_ints_vector = list_of(0)(1)(1)(2)(3)(5)(8)(13)(21)(34);
    
    struct ScopedStruct1
    {
            ScopedStruct1(const vector<int> & v) : m_v(v) {}
            ~ScopedStruct1() {}
        private :
            vector<int> m_v;
    };
    
    class A 
    { 
        public :
            A(int i) : m_i(i) {}
            ~A() {}
        private :
            int m_i;
    };
    
    struct ScopedStruct2
    {
        ScopedStruct2() {}
        ~ScopedStruct2() { for(vector<A*>::iterator it = m_v.begin(); it != m_v.end(); ++it) delete *it; }
    
        vector<A*> m_v;
    };
    
    struct ScopedStruct3
    {
        ScopedStruct3() {}
        ~ScopedStruct3() { /* no deletion */ }
    
        vector<A*> m_v;
    };
    
    BOOST_AUTO_TEST_CASE(StlContainer_storing_something_simple)
    {
        ScopedStruct1 str(my_ints_vector);
    }
    
    BOOST_AUTO_TEST_CASE(StlContainer_storing_pointers_with_delete)
    {
        ScopedStruct2 str;
        for(int i = 0; i < 10; i++)
            str.m_v.push_back(new A(i));
    }
    
    BOOST_AUTO_TEST_CASE(StlContainer_storing_pointers_without_delete)
    {
        ScopedStruct3 str;
        for(int i = 0; i < 10; i++)
            str.m_v.push_back(new A(i));
    }
    
    #定义BOOST_TEST_模块
    #定义BOOST_LIB_诊断
    #包括
    #包括
    #包括
    #包括
    #包括
    使用名称空间boost::assign;
    使用名称空间std;
    常量向量my_ints_vector=列表(0)(1)(1)(2)(3)(5)(8)(13)(21)(34);
    结构范围结构1
    {
    ScopedStruct1(const vector&v):m_v(v){}
    ~ScopedStruct1(){}
    私人:
    向量m_v;
    };
    甲级
    { 
    公众:
    A(int i):m_i(i){}
    ~A(){}
    私人:
    国际货币基金组织;
    };
    结构范围结构2
    {
    ScopedStruct2(){}
    ~ScopedStruct2(){for(vector::iterator it=m_v.begin();it!=m_v.end();++it)delete*it;}
    向量m_v;
    };
    结构范围结构3
    {
    ScopedStruct3(){}
    ~ScopedStruct3(){/*无删除*/}
    向量m_v;
    };
    BOOST\u AUTO\u TEST\u案例(StlContainer\u storage\u something\u simple)
    {
    ScopedStruct1 str(我的输入向量);
    }
    BOOST\u AUTO\u TEST\u案例(StlContainer\u存储\u指针\u和\u delete)
    {
    范围结构2;
    对于(int i=0;i<10;i++)
    str.m_v.推回(新的A(i));
    }
    BOOST\u AUTO\u TEST\u案例(StlContainer\u存储\u指针\u而不删除)
    {
    范围结构3;
    对于(int i=0;i<10;i++)
    str.m_v.推回(新的A(i));
    }
    
    使用boost的单元测试框架,我创建了3个测试用例。单元测试框架是伟大的,因为它跟踪内存泄漏。
    您会注意到,第一个和第二个测试用例不会产生内存泄漏,但第三个测试用例会产生内存泄漏,因为向量的内容没有被删除。

    当然,在解除分配之前,必须调用析构函数中的clear()或resize(0)或等效语句(std:_Destroy_range(…)。

    解除分配是通过分配器::解除分配完成的,它不运行任何析构函数。它只是释放内存

    clear()相当于resize(0),它在分配的缓冲区中的第一个size()对象上运行析构函数


    不仅仅是分配的指针、文件句柄、持有的互斥体、对象持有的所有其他可恢复资源。必须运行析构函数。在实例化之前,模板不知道析构函数是平凡的。如果析构函数是平凡的,那么它在实例化后会得到优化。

    我能想到的唯一一种情况是它会在哪里运行e有用是指销毁顺序很重要,析构函数希望确保向量中的对象在其他对象之前被销毁


    当然,构建代码时最好不要要求这样做;然而,这是一个可以想象的原因。

    尽管到目前为止已经说过,至少有一种情况下,可能需要在析构函数中显式调用
    clear

    想象一下,当要销毁的对象有多个成员子对象时,这些成员子对象需要某种特定的销毁顺序,即子对象在某种程度上相互依赖,错误的销毁顺序将导致不希望的结果。您可能知道,成员子对象的销毁顺序(以及成员初始化)是由类定义中成员声明的顺序决定的。因此,实现正确的销毁顺序的一种方法是相应地安排成员声明。但是,首先,从维护角度来看,这不是一个很好的解决方案。其次,所需的销毁顺序可能取决于某些运行时条件。第三,desi红色的销毁顺序可能与所需的初始化顺序相矛盾。这都意味着,通过重新安排decl命令正确的销毁顺序可能是不可能的(或明智的)