簡體   English   中英

構造函數和析構函數中的std :: vector :: clear()

[英]std::vector::clear() in constructor and destructor

我在代碼中多次遇到std :: vector類型為std :: vector的類成員的std :: vector :: clear()在構造函數和析構函數中調用。

我不明白為什么需要它:

  1. 構造函數 - 默認情況下,類型為std :: vector的類成員為空,因此無需調用clear()。
  2. 析構函數 - 類型為std :: vector的類成員將被銷毀,作為對象的標准銷毀的一部分。 作為向量銷毀的一部分,包含在其中的所有值對象都將被銷毀(如果它分配指向內存的指針,則應該“手動”刪除它們),因此再次不需要調用clear()。

我錯過了什么嗎?

不,你沒有遺漏任何東西。 我懷疑這是(無害的)voodoo編程,有點像在釋放它之后將指針設置為null,或者在GUI代碼中隨機調用repaint / revalidate。 程序員記得它曾經幫助過某種類型的錯誤,現在不必要地添加它“以防萬一”。 誰知道,也許它會有所幫助。 巫毒。

從事物的聲音來看,編寫該代碼的人是那些錯過了某些東西的人。 在ctor或dtor中調用clear()的唯一時間是在其他代碼的中間。 例如,ctor可能讀入一些數據,處理它,然后讀入更多數據。 在這種情況下,在讀取數據時使用單個容器可能會更快,並且每次都清除它,而不是每次迭代創建一個新容器。

  1. 它是完全 unnessecary以清除在構造一個STL容器的內容
  2. 清除析構函數中stl容器的內容是不可靠的, 除非容器包含指針。 如果指針是使用new創建的,則仍需要先刪除它。 在此之后,仍然不會對.clear容器感到厭煩。

考慮一下:

#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的unit_test框架我創建了3個測試用例。 unit_test框架是greate,因為它跟蹤內存泄漏。 你會注意到第一和第二個測試用例不會產生內存泄漏,但第三種情況是因為沒有刪除向量的內容。

不,你說得對。 除非在構造函數(或基類的構造函數)中有一些額外的業務需要,但機會非常低......

稍后編輯

在析構函數的情況下,我看到的一個最常見的錯誤是有些人認為clear方法也會調用指針向量的刪除(向量),當然,情況並非如此

我能想到的唯一一個有用的地方就是破壞的順序很重要,析構函數想要確保向量中的對象在其他東西之前被銷毀。

當然,最好將代碼結構化為不需要; 然而,這是一個可以想象的原因。

盡管到目前為止所說的內容,至少有一種情況是在析構函數中顯式調用clear可能是必要的。

想象一下當被銷毀的對象有幾個成員子對象時的情況,這些子對象需要一些特定的破壞順序,即子對象以某種方式相互依賴,並且不正確的破壞順序將導致不良結果。 您可能知道,成員子對象銷毀(以及成員初始化)的順序由類定義中成員聲明的順序決定。 因此,實現正確破壞順序的一種方法是相應地安排成員聲明。 但是,首先,這不是一個非常好的維護解決方案。 其次,所需的破壞順序可能取決於某些運行時條件。 第三,所需的破壞順序可能與所需的初始化程序相矛盾。 這一切都意味着通過重新安排聲明來指揮正確的破壞順序可能是不可能的(或明智的)。

在這種情況下,合理的方法可能是通過調用它們的clean方法等手動清理一些關鍵成員子對象,直到破壞順序依賴“消失”。 我猜,也許你看到的代碼試圖通過在戰略選擇的vector量子對象上調用clean來解決排序問題。

至於在構造函數中調用clean ...我不知道為什么有人會這樣做。

當然,在解除分配之前,必須在析構函數中調用clear()或resize(0)或等效的say(std :: _ Destroy_range(...)。

解除分配是通過allocator :: deallocate完成的,它不運行任何析構函數 它只是釋放了記憶。

clear()等效於resize(0),它在分配的緩沖區中的第一個size()事物上運行析構函數

不只是分配了指針,文件句柄,保持的互斥鎖,以及對象持有的所有其他可恢復資源。 必須運行析構函數。 在實例化之前,模板不知道析構函數是微不足道的。 如果析構函數是微不足道的,那么在實例化之后它就會被優化掉

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM