这会限制类仅在当前帧中具有生存期吗?

Would this restrict the class to be have a lifetime in the current frame only?

本文关键字:生存期      更新时间:2023-10-16

我想将特定类限制为仅在堆栈上创建(而不是通过分配)。这样做的原因是,在堆栈上,生命周期最后开始的对象将是第一个被销毁的对象,我可以创建一个层次结构。我是这样做的:

#include <cstddef>
#include <iostream>
class Foo {
public:
  static Foo createOnStack() {
    return {};
  }
  ~Foo () {
    std::cout << "Destructed " << --i << std::endl;
  }
protected:
  static int i;
  Foo () {
    std::cout << "Created " << i++ << std::endl;
  }
  Foo (const Foo &) = delete;
};
int Foo::i = 0;

构造函数通常应该推送层次结构堆栈,析构函数会弹出它。我在这里替换了它以证明概念。现在,使用此类对象的唯一方法是将其存储在临时引用中,如下所示:

int main() {
  Foo && a = Foo::createOnStack();
  const Foo& b = Foo::createOnStack();
  return 0;
}

我现在的问题是,这在C++标准下有多安全?是否还有一种方法可以在堆上合法地创建一个Foo或将其从您的函数传递到另一个帧(也就是从您的函数返回它),而不会遇到未定义的行为?


编辑:链接到示例 https://ideone.com/M0I1NI

撇开protected后门不谈,C++17 copy elision 以两种方式打破了这一点:

#include<iostream>
#include<memory>
struct S {
  static S make() {return {};}
  S(const S&)=delete;
  ~S() {std::cout << '-' << this << std::endl;}
private:
  S() {std::cout << '+' << this << std::endl;}
};
S reorder() {
  S &&local=S::make();
  return S::make();
}
int main() {
  auto p=new S(S::make()),q=new S(S::make());  // #1
  delete p; delete q;
  reorder();                                   // #2
}
  1. new的使用是显而易见的,并且已经进行了讨论。
  2. C++17 还允许 prvalue 通过堆栈帧传播,这意味着可以在返回值之前创建local,并在该返回值处于活动状态时销毁。

请注意,在 local 属于类型 S 但返回值是其他(可移动)类型的情况下,第二种情况已经存在(正式在 C++14 中,很久以前非正式地存在)。 一般来说,您不能假设即使是自动对象生存期也能正确嵌套。