为什么在函数内部初始化时 C++ 对象会被破坏?我能做些什么来防止它?

问题描述

这里,当我入栈时,为什么对象被销毁了?

#include <iostream>
#include <stack>

class One
{
private:
        int i;
public:
        One(int i) {this->i = i;}
        ~One() {std::cout << "value " << this->i << " is destroyed\n";}
};

int main()
{
        std::stack<One> stack;
        stack.push(One(1));
        stack.push(One(2));

        std::cout << "Now I'll stop\n";
}

我希望在 Now I'll stop 之前看不到任何输出。但我明白了

value 1 is destroyed
value 2 is destroyed
Now I'll stop
value 1 is destroyed
value 2 is destroyed

如果我想防止它们被破坏,我该怎么做?

解决方法

One(1)One(2) 构造两个临时对象,将它们传递给 push,然后复制(移动)到 stack 中。临时表在完整表达式后立即销毁。

如果您想避免构建临时文件,您可以改用 emplace

将一个新元素压入栈顶。元素是就地构造的,即不执行复制或移动操作。

例如

stack.emplace(1);
stack.emplace(2);
,

让我在解决实际问题的 songyuanyao's answer 中添加一个说明性细节。

如果您将 copy constructor 添加到类 One,您将更容易理解发生了什么以及如何保持创建和销毁之间的平衡。 (对你来说,两个创造物获得 4 次破坏是不是很神奇?)

只要您没有定义(或提及)copy constructor,编译器就会为您创建一个具有简单实现的实现,该实现对所有成员进行按位复制。因此,在您的情况下,您观察到的行为可能令人困惑,但并没有做任何特别糟糕的事情。这当然会在您添加涉及不仅仅是复制的成员时立即改变,例如指向必须在某处销毁的成员的指针......

在以下示例中,我向两个构造函数都添加了输出,并且还从在构造函数主体中分配成员切换为 initialiser list

class One
{
  public:
    One(int rhs): i(rhs) {
        std::cout<< "value " << i << " was created from int\n";
    }
    One(const One& rhs): i(rhs.i) {
        std::cout<< "value " << i << " was created by copy\n";
    }
    ~One() {
        std::cout << "value " << i << " is destroyed\n";
    }

  private:
    int i;
};
,

执行此操作时 stack.push(One(1)); 会创建一个名为 One(1) 的 rvalue 的临时对象,然后将其复制到 Stack。所以在 Copy 之后,临时对象会被销毁。