简体   繁体   English

C++ 析构函数多次破坏对象

[英]C++ destructor destroys objects couple times

I am new in C++ so have a question.我是 C++ 的新手,所以有一个问题。

There is C++ code:有 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();
}

And this is output:这是 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

Why compiler destroy objects in vector couple times, when must do it once?为什么编译器会破坏向量中的对象几次,什么时候必须做一次? What wrong in that code?该代码有什么问题?

Compile Microsoft cl.exe x64 with default options.使用默认选项编译 Microsoft cl.exe x64。

Let's add a copy constructor (and use a smaller test case, to cut the verbosity) and see what happens...让我们添加一个复制构造函数(并使用一个较小的测试用例,以减少冗长),看看会发生什么......

#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();
}

This produces这产生

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

Explanation:解释:

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

If you loop over references, i will refer to the object inside the vector instead of a copy of it - just changing one line to如果您循环引用, i将引用向量内的 object 而不是它的副本 - 只需将一行更改为

for (auto& i : test)

changes the output to将 output 更改为

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

And you can get rid of further copying by creating the object inside the vector directly:您可以通过直接在向量内创建 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: Output:

Original
Loop:
This is Original
Clear
Destroy Original

What wrong in that code?该代码有什么问题?

main must return int . main必须返回int It must not return void .它不能返回void To fix this, change the return type to int要解决此问题,请将返回类型更改为int

Other than that, your expectations are wrong.除此之外,您的期望是错误的。

When you create a variable or a temporary object, it will be destroyed.当您创建变量或临时 object 时,它将被销毁。 When you create a copy of an object, both the copy and the original object will be destroyed eventually (except for cases involving memory leaks).当您创建 object 的副本时,副本和原始 object 最终都将被销毁(涉及 memory 泄漏的情况除外)。

Because in the for loop:因为在for循环中:

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

you're actually creating another copy of the Test elements in std::vector<Test> test , not the element itself, so that's why it creates (and destroys another copy)您实际上是在std::vector<Test> test中创建Test元素的另一个副本,而不是元素本身,所以这就是它创建(并销毁另一个副本)的原因

Change your for loop to:将您的for循环更改为:

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

produce:生产:

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

which is what you expect:这是你所期望的:

Try it live (including all the proper headers)现场试用(包括所有正确的标题)


Also, main() returns an int , so change your main() definition to:此外, main()返回一个int ,因此将main()定义更改为:

int main()

int main() not void main() . int main()不是void main() Your compiler should have warned you about that.你的编译器应该已经警告你了。 Make sure you enable your compiler warnings.确保启用编译器警告。

for (auto i: test) makes a copy of the object. for (auto i: test)复制object。 You probably wanted for (auto&& i: test) or for (auto const& i: test) .您可能想要for (auto&& i: test)for (auto const& i: test) Note that auto&& has a bit of a different meaning than Test&& , since auto&& follows the template rules.请注意, auto&&Test&&有一点不同的含义,因为auto&&遵循模板规则。

The code neglects to consider the implicit copy constructor .代码忽略了隐式复制构造函数 Here I've added one in, which should help significantly for understanding what is going on:在这里,我添加了一个,这应该有助于理解正在发生的事情:

#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