簡體   English   中英

C++ 析構函數多次破壞對象

[英]C++ destructor destroys objects couple times

我是 C++ 的新手,所以有一個問題。

有 C++ 代碼:

class Test
{        
    public:
        std::string name;
        Test(){};
        Test(std::string name) {
        
            std::cout << "Create " << name << '\n';
            Test::name = name;
        };
        ~Test() {std::cout << "Destroy " << name << '\n';} 
};

std::vector<Test> test {Test("one"), Test("two"), Test("three")};

void main()
{
    for (auto i : test)
        std::cout << i.name << '\n';
    
    std::cout << "Clear\n";
    test.clear();
}

這是 output:

Create one
Create two
Create three
Destroy three
Destroy two
Destroy one
one
Destroy one
two
Destroy two
three
Destroy three
Clear
Destroy one
Destroy two
Destroy three

為什么編譯器會破壞向量中的對象幾次,什么時候必須做一次? 該代碼有什么問題?

使用默認選項編譯 Microsoft cl.exe x64。

讓我們添加一個復制構造函數(並使用一個較小的測試用例,以減少冗長),看看會發生什么......

#include <iostream>
#include <string>
#include <vector>

class Test
{        
    public:
        std::string name;
        Test(){};
        Test(std::string name) : name(name) {        
            std::cout << "New " << name << '\n';
        }
        Test(const Test& other) : name("Copy of " + other.name) {
            std::cout << "Copied " << other.name << '\n';
        }
        ~Test() {std::cout << "Destroy " << name << '\n';} 
};

std::vector<Test> test {Test("Original") };

int main()
{
    std::cout << "Loop:\n";
    for (auto i : test)
        std::cout << "This is " << i.name << '\n';   
    std::cout << "Clear\n";
    test.clear();
}

這產生

New Original
Copied Original
Destroy Original
Loop:
Copied Copy of Original
This is Copy of Copy of Original
Destroy Copy of Copy of Original
Clear
Destroy Copy of Original

解釋:

New Original -- The object in the initialzer list
Copied Original -- Here it gets copied into the vector
Destroy Original -- The original is destroyed along with the initializer list
Loop:
Copied Copy of Original -- Copied into the loop variable
This is Copy of Copy of Original -- Printing in the loop
Destroy Copy of Copy of Original -- The temporary loop object is destroyed
Clear
Destroy Copy of Original -- Clearing the vector

如果您循環引用, i將引用向量內的 object 而不是它的副本 - 只需將一行更改為

for (auto& i : test)

將 output 更改為

New Original
Copied Original
Destroy Original
Loop:
This is Copy of Original
Clear
Destroy Copy of Original

您可以通過直接在向量內創建 object 來擺脫進一步的復制:

int main()
{
    std::vector<Test> test;
    test.emplace_back("Original");
    std::cout << "Loop:\n";
    for (auto& i : test)
        std::cout << "This is " << i.name << '\n';   
    std::cout << "Clear\n";
    test.clear();
}

Output:

Original
Loop:
This is Original
Clear
Destroy Original

該代碼有什么問題?

main必須返回int 它不能返回void 要解決此問題,請將返回類型更改為int

除此之外,您的期望是錯誤的。

當您創建變量或臨時 object 時,它將被銷毀。 當您創建 object 的副本時,副本和原始 object 最終都將被銷毀(涉及 memory 泄漏的情況除外)。

因為在for循環中:

for (auto i : test)
    std::cout << i.name << '\n';

您實際上是在std::vector<Test> test中創建Test元素的另一個副本,而不是元素本身,所以這就是它創建(並銷毀另一個副本)的原因

將您的for循環更改為:

for (auto &i : test) // reference:
    std::cout << i.name << '\n';

生產:

Create one
Create two
Create three
Destroy three
Destroy two
Destroy one
one
two
three
Clear
Destroy one
Destroy two
Destroy three

這是你所期望的:

現場試用(包括所有正確的標題)


此外, main()返回一個int ,因此將main()定義更改為:

int main()

int main()不是void main() 你的編譯器應該已經警告你了。 確保啟用編譯器警告。

for (auto i: test)復制object。 您可能想要for (auto&& i: test)for (auto const& i: test) 請注意, auto&&Test&&有一點不同的含義,因為auto&&遵循模板規則。

代碼忽略了隱式復制構造函數 在這里,我添加了一個,這應該有助於理解正在發生的事情:

#include <iostream>
#include <string>
#include <utility>
#include <vector>

struct Test {
    std::string name;

    ~Test() {
        std::cout << "Destroy " << name << "\n";
    }

    Test() {
        std::cout << "Default-Create (empty)\n";
    }

    Test(std::string name_) : name{std::move(name_)} {
        std::cout << "Create " << name << "\n";
    }

    Test(Test const& other) : name{other.name + "!"} {
        std::cout << "Create-by-Copy " << name << "\n";
    }
};

int main() {
    auto test = std::vector<Test>{Test{"one"}, Test{"two"}, Test{"three"}};

    for (auto i : test)
        std::cout << i.name << "\n";

    std::cout << "Clear\n";
    test.clear();
}

暫無
暫無

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

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