繁体   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