是否可以将堆栈对象地址赋给placement new

Is it okay to give a stack object address to placement new?

本文关键字:placement new 地址 对象 堆栈 是否      更新时间:2023-10-16

忽略了这种做法的有用性。(当然,现实生活中的例子是受欢迎的。)

例如,以下程序输出a的正确值:

#include <iostream>
using namespace std;
int main()
{
  int a = 11111;
  int i = 30;
  int* pi = new (&i) int();
  cout << a << " " << endl;
}

但是new-allocation是不是应该在i附近创建一些簿记信息(为了正确的后续释放),在这种情况下应该破坏i周围的堆栈?

是的,对指向堆栈上对象的指针执行place -new是完全可以的。它只会使用那个特定的指针来构造对象。placementnew实际上并没有分配任何内存——您已经提供了这一部分。它只做构造。随后的删除实际上不会是delete—没有位置delete—因为您所需要做的就是调用对象的析构函数。实际的内存是由其他东西管理的——在这个例子中是堆栈对象。

例如,给定这个简单类型:

struct A {
    A(int i) 
    : i(i)
    {
        std::cout << "make an An";
    }
    ~A() {
        std::cout << "delete an An";
    }
    int i;
};

下面是完全合理的,行为良好的代码:

char buf[] = {'x', 'x', 'x', 'x', 0};
std::cout << buf << std::endl;  // xxxx
auto a = new (buf) A{'a'};      // make an A
std::cout << a->i << std::endl; // 97
a->~A();                        // delete an A

唯一无效的情况是,如果您的放置-新建对象的存续期超过了您新建的对象的存续期——出于同样的原因,返回悬空指针总是不好的:

A* getAnA(int i) {
    char buf[4];
    return new (buf) A(5); // oops
}

new位置将构造元素的位置,并且不分配内存。

本例中的"簿记信息"是返回的指针,应该用来销毁放置的对象。

没有与位置相关的删除操作,因为位置是一个构造。因此,放置new所需的"清理"操作是销毁。

"通常步骤"为

  1. 分配的内存
  2. 在适当位置构建元素
  3. 销毁元素(2的反转)
  4. 'Deallocate'内存(1的反转)

(其中内存可以是堆栈内存,既不需要显式分配也不需要释放,而是随着堆栈数组或对象来来回回)

注意:如果将对象"放置"到堆栈中相同类型的内存中,应该记住在对象的生命周期结束时将自动销毁。

{ 
  X a;
  a.~X(); // destroy a
  X * b = new (&a) X(); // Place new X
  b->~X(); // destroy b
} // double destruction

不可以,因为您不需要delete一个已经更新了位置的对象,所以您需要手动调用它的析构函数。

struct A {
    A() { std::cout << "A()n"; }
    ~A() { std::cout << "~A()n"; }
};
int main()
{
    alignas(A) char storage[sizeof(A)];
    A *a = new (storage) A;
    std::cout << "hi!n";
    a->~A();
    std::cout << "bye!n";
}
输出:

A()
hi!
~A()
bye!

在你的例子中,也不需要调用析构函数,因为int是平凡可析构的,这意味着它的析构函数无论如何都是无操作的。

请注意,不要在仍然存活的对象上调用place -new,因为不仅会破坏它的状态,而且它的析构函数也会被调用两次(一次是在手动调用时,还有一次是在原始对象应该被删除时,例如在其作用域结束时)。

新增的是建设,而不是分配,因此无需担心记账信息。

我现在可以想到一个可能的用例,尽管它(以这种形式)将是一个糟糕的封装示例:

#include <iostream>
using namespace std;
struct Thing {
 Thing (int value) {
  cout << "such an awesome " << value << endl;
 }
};
union Union {
 Union (){}
 Thing thing;
};
int main (int, char **) {
 Union u;
 bool yes;
 cin >> yes;
 if (yes) {
  new (&(u.thing)) Thing(42);
 }
 return 0;
}

住在这里

即使在某个成员函数中隐藏了位置new,构造仍然在堆栈上进行。

So:我没有看标准,但是不明白为什么不允许在堆栈上放置new。

一个真实世界的例子应该在https://github.com/beark/ftl…在它们的递归联合中,用于sum类型