【问题标题】:Is the Object Destroyed in that Case?在这种情况下对象是否被破坏?
【发布时间】:2021-10-04 06:52:33
【问题描述】:

当我有一个函数时,我们称它为foo()。在foo() 中,我创建了一个名为obj1 的对象,它是ClassA 的一种类型。另外,我将对象的引用复制到std::queue<ClassA&> qu

我的问题是:对象obj1foo() 返回之前被销毁了吗?

代码示例:

class ClassA {...};

std::queue<ClassA&> qu;

void foo()
{
    ClassA obj1;
    qu.push_back(obj1);
}

int main()
{
    foo();
    return 0;
}

【问题讨论】:

  • 请粘贴完整示例。这取决于。
  • @pptaszni:一个minimal reproducible example,就是这样。
  • 如果它是本地的自动范围,那么是的(并且引用现在悬空且不可用,除非队列也超出范围)。请显示实际代码,因为如果您使用new,答案会有所不同。
  • 这不会编译,但如果编译了,obj1 会在超出范围时被销毁。在这种情况下,当函数返回时,它将超出范围。

标签: c++


【解决方案1】:

您不能将引用用作队列的元素。您也不能将引用用作任何其他标准容器的元素。因此,显示的程序格式不正确。

也就是说,obj1 是一个自动变量,因此它在作用域结束时被销毁,在这种情况下是函数返回时。

【讨论】:

  • 出于好奇——如果ClassA 有一个普通的析构函数,obj 是否也被销毁(它的析构函数被调用),或者它的生命周期仅仅通过释放它的存储空间就结束了?
  • @Daniel:析构函数被调用。
  • @ThomasWilde 请您指出 C++ 标准中这样说的部分吗?
  • @DanielLangr 先this 然后this
【解决方案2】:

obj1 在堆栈上创建。一旦堆栈上的变量超出范围,它就会被销毁。当foo() 结束时,obj1 超出范围。因此obj1 被销毁,并调用其析构函数。

此外,您不能将引用存储在像 queue 这样的 STL 容器中。您可以改用指针或std::reference_wrapper

看看这个例子:

#include <functional>
#include <iostream>
#include <queue>

using namespace std;
// ---------------------------------------------------------- //
struct ClassA {
  ClassA(string name)
    : name_(name) {
    cout << "create " << name << endl;
  }

  ~ClassA() { cout << "destroy " << name_ << endl; }

  int    x     = 42;
  string name_ = "";
};

// ---------------------------------------------------------- //
void
foo1() {
  cout << "start foo1()" << endl;
  ClassA obj("foo1_object");

  queue<ClassA*> foo1_queue;
  foo1_queue.push(&obj);
  cout << "end foo1()" << endl;
}

// ---------------------------------------------------------- //
void
foo2(queue<ClassA*>& queue) {
  cout << "start foo2()" << endl;
  ClassA obj("foo2_object");
  queue.push(&obj);
  cout << "end foo2()" << endl;
}

// ---------------------------------------------------------- //
void
foo3(queue<reference_wrapper<ClassA>>& queue) {
  cout << "start foo3()" << endl;
  ClassA obj("foo3_object");
  queue.push(obj);
  cout << "end foo3()" << endl;
}

// ---------------------------------------------------------- //
int
main(int argc, char const* argv[]) {
  cout << "main before foo1()" << endl;
  foo1();
  cout << "main after foo1()" << endl;
  cout << endl;
  // ---
  cout << "main before foo2()" << endl;
  queue<ClassA*> main_queue1;
  foo2(main_queue1);
  cout << "main after foo2()" << endl;
  cout << endl;

  // ---
  cout << "main before foo3()" << endl;
  queue<reference_wrapper<ClassA>> main_queue2;
  foo3(main_queue2);
  cout << "main after foo3()" << endl;
  cout << endl;
}

这给出了以下输出:

main before foo1()
start foo1()
create foo1_object
end foo1()
destroy foo1_object
main after foo1()

main before foo2()
start foo2()
create foo2_object
end foo2()
destroy foo2_object
main after foo2()

main before foo3()
start foo3()
create foo3_object
end foo3()
destroy foo3_object
main after foo3()

【讨论】:

  • 你可以使用std::reference_wrapper代替指针。
  • @DevSolar:我添加了一个使用 reference_wrapper 的示例
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-26
  • 2020-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-01
相关资源
最近更新 更多