为什么将一个对象推入向量中会被销毁?

3
我想知道为什么在这种情况下,我将一个元素推回向量中时,它的析构函数会被调用:
#include <iostream>
#include <vector>

class Foo
{
public:
    Foo(int a)
     : m_a(a)
    {
        std::cout << "Foo ctor() " << m_a << std::endl;
    }
    ~Foo()
    {
        std::cout << "Foo dtor() " << m_a << std::endl;
    }
private:
    int m_a;
};

class FooStorage
{
public:
    static void createFoo(int a)
    {
        m_foos.push_back(Foo(a));
    }

    static std::vector<Foo> m_foos;
};

std::vector<Foo> FooStorage::m_foos;

int main()
{
    std::cout << "Before: " << FooStorage::m_foos.size() << std::endl;
    FooStorage::createFoo(53);
    std::cout << "After: " << FooStorage::m_foos.size() << std::endl;

    return 0;
}

这将打印以下内容:

Before: 0
Foo ctor() 53
Foo dtor() 53
After: 1
Foo dtor() 53

我想知道:

  • 什么会被删除?(在“Before”和“After”之间的内容)
  • 为什么会被删除?
  • 最终会有什么存储在向量中?

FooStorage类的意义是什么?它只是让阅读变得更困难。 - undefined
如果你不想复制它,将其复制到你的向量中,请使用Foo&或Foo*进行存储。 - undefined
2
使用emplace_back函数直接在向量中创建对象。 - undefined
2
@AlexanderBrevig 使用引用是行不通的,因为它们无法被复制。 - undefined
@NeilKirk 啊,就是这样了。我的错。 :) - undefined
显示剩余5条评论
2个回答

9
您在此处创建了一个临时对象:

m_foos.push_back(Foo(a));
//               ^^^^^^

当完整表达式结束时,该对象的析构函数将被调用,但它已经被复制(或移动)到向量中通过push_back()

为了防止创建临时对象,您可以使用emplace_back()进行就地构造:

m_foos.emplace_back(a);

这在IDE上不起作用,IDE本身就是问题所在。试着从终端编译。 - undefined
编译器和运行时没有任何显示,但结果完全错误且存在未定义的行为。请查看以下链接中的最佳答案:https://dev59.com/E2855IYBdhLWcg3wg0nC我发表了这个评论,因为我花了几个小时来调试一个来自CLion的bug,而从终端运行的代码完全正常。在这种情况下,我不需要使用emplace_backpush_back就可以工作。 - undefined

1
m_foos.push_back(Foo(a));

这将导致两个构造函数的调用(但完全取决于编译器,它可以进行优化)。
Foo(a)

这是一个临时对象,会被创建(一次构造函数的调用),然后复制到向量中(调用复制构造函数)。通常情况下,临时对象会一直存在,直到使用它们的表达式结束为止。因此,当push_back结束时,它会调用此临时对象的析构函数(这就是为什么你看到了一次析构函数的调用)。


1
这里不能省略复制/移动构造函数。调用哪一个取决于情况。在这种情况下,因为存在用户声明的析构函数,所以调用的是复制构造函数。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接