2016-05-31 169 views
0

我想要下面的代碼創建5個類「test」的對象,每次創建時調用構造函數,將它們存儲在一個向量中,打印「lalalala」一次,然後運行析構函數並銷燬創建的對象。我希望析構函數爲我創建的每個對象運行一次,但不要超過一次。C++中的構造函數和析構函數與C#比較

我認爲在下面的例子中,C++創建了多個不需要的對象的副本,否則它會調用析構函數多次。我不確定。試過海灣合作委員會和鏗鏘沒有區別。嘗試堆棧和堆分配,以及std :: move。所有產生相同的結果,方式更多的析構函數調用比我所要求的。

另外我注意到一些但不是所有的C++析構函數在我打印「lalala」之前調用。

爲什麼這個C++代碼運行析構函數的17倍:

#include <iostream> 
#include <vector> 

using namespace std; 


class test 
{ 
public: 
    int t; 
    test(int i) 
    { 
     t = i; 
     cout << "Created instance " << t << ". \n"; 
    } 
    ~test() 
    { 
     cout << "(*)Deleted instance " << t << ".\n"; 
    } 
}; 

int main() 
{ 
    vector <test> V; 

    for(int i = 1; i <= 5; i++) 
    { 
     test D(i); 
     V.push_back(D); 
    } 
    cout << "LALALLALA \n"; 
    return 0; 
} 

雖然此C#代碼不正是我想要的東西,5構造函數和析構函數5。

using System.IO; 
using System; 
using System.Collections.Generic; 
class Program 
{ 
    class test 
    { 
     public int t; 
     public test(int i) 
     { 
      t = i; 
      Console.Write ("Created instance "); 
      Console.Write (t.ToString()); 
      Console.WriteLine("."); 
     } 

     ~test() 
     { 
      Console.Write("(*)Deleted instance "); 
      Console.Write(t.ToString()); 
      Console.WriteLine("."); 
     } 

    } 
    static void Main() 
    { 
     List<test> lst = new List<test>(); 
     for(int i = 0; i < 5; i++) 
     { 
      test temp = new test(i); 
      lst.Add(temp); 
     } 
     Console.WriteLine("LALALLALA \n"); 
    } 
} 
+2

您還需要計數複製構造函數。 – SergeyA

+0

http://stackoverflow.com/a/2625089/1060270說明可能有幫助 – amit

回答

3

在C#中,您的列表存儲對對象的引用。在C++中,實際上是將對象存儲在向量中。這意味着當它們被放入向量時,以及向量需要重新分配時,它們需要被複制。這些副本中的每一個都是一個單獨的對象(使用複製構造函數創建,不跟蹤),並且將調用析構函數。

C++中的近似於你在C#中的所作所爲將存儲指針(或智能指針)堆中分配的測試對象,而不是測試對象本身

#include <memory> // for shared_ptr 

int main() 
{ 
    std::vector<std::shared_ptr<test>> V; 

    for(int i = 1; i <= 5; i++) 
    { 
     auto D = std::make_shared<test>(i); 
     V.push_back(D); 
    } 
    std::cout << "LALALLALA \n"; 
    return 0; 
} 

優選的慣用C++的做法,如果你想確保你只是創建5個對象,但不必分配在堆上的每個對象將是以下內容:

int main() 
{ 
    std::vector<test> V; 

    // ensure we can store 5 objects without reallocating 
    V.reserve(5); 

    for(int i = 1; i <= 5; i++) 
    { 
     // construct the object in place in the vector 
     V.emplace_back(i); 
    } 
    std::cout << "LALALLALA \n"; 
    return 0; 
} 
3

在C++中缺少複製構造函數會增加構造函數調用和析構函數調用的報告數量之間的不匹配。有很多副本創建(數量取決於執行/編譯器允許的優化)。

注意,你是比較蘋果和橘子(兩次):

  • C++對象是默認值類型,而C#類是引用類型(和C#的值類型 - struct不能有析構函數) 。所以,如果你的C++代碼會使用包裝成某種智能指針的指針(這樣也避免了缺少複製構造函數的問題),你會得到相同的行爲。

  • C++析構函數是同步的,而C#「析構函數」是異步的,並且可能永遠不會運行(與C++相比,當對象超出範圍時肯定不會運行)。