第二行是什么?(在回答另一个问题时看到。)
int * x = new int [1] ;
int * y = new (x) int;
在第二行之后 x 和 y 具有相同的值(指向同一个地方)。y = x 和第二行有什么区别?它像构造函数还是什么?
第二行是什么?(在回答另一个问题时看到。)
int * x = new int [1] ;
int * y = new (x) int;
在第二行之后 x 和 y 具有相同的值(指向同一个地方)。y = x 和第二行有什么区别?它像构造函数还是什么?
它的位置新。int
它在 指向的内存中构造一个新的x
。
如果你试试:
int * x = new int [1];
*x = 5;
std::cout << *x << std::endl;
int * y = new (x) int;
*y = 7;
std::cout << *x << std::endl;
输出将是:
5
7
这称为放置新。它允许您在已分配的内存中构造一个对象。
这个较早的线程讨论了它在何处以及如何用于.
这是新的安置。
尽管您通常不将其与整数类型一起使用。
它通常用于构建缓冲区,然后在其中构建其他类型。
// Allocate a buffer with enough room for two T objects.
char* buffer = new char[sizeof(T) * 2];
// Allocate a T in slot zero
T* t1 = new (buffer + 0 * sizeof(T)) T("Zero");
// Allocate a T in slot one
T* t2 = new (buffer + 1 * sizeof(T)) T("One");
这就是基础。
但请记住,使用placement new 分配的对象不能用delete
语句删除。这是因为delete
试图回收分配的内存new
(以及调用析构函数)。因此,要正确使用这些对象,您必须手动调用那里的析构函数。
t1->~T();
t2->~T();
不要忘记删除原始缓冲区。
delete [] buffer;
其他一些注意事项:
人们经常看到缓冲区可以在堆栈上实现,因此可以自动释放
char buffer[sizeof(T) * 2];
不幸的是,这在技术上可能没问题(它可以编译)。但它不能保证工作,因为缓冲区的内存可能无法正确对齐以将 T 放置在其中。因此,您必须动态分配缓冲区(通过使用 new 它保证内存针对分配的任何大小的对象正确对齐(因此通过扩展,它也针对小于分配大小的任何大小对齐)。绕过的简单方法这个问题是使用 std::vector
std::vector<char> buffer(sizeof(T) * 2);
T* t1 = new (&buffer[0] + 0 * sizeof(T)) T("Zero");
T* t2 = new (&buffer[0] + 1 * sizeof(T)) T("One");
Placement new 的另一个用途是重置对象。
我已经看到这样做了,但我更喜欢使用更标准的赋值运算符:
T obj1("Plop");
obj1 = T("Another Plop");
// Can be done like this:
T obj1("Plop");
obj1.~T();
new (&obj1) T("Another Plop"); // Seems excessive to me. But can be us-full
// in some extreme situations.
请记住,如果您使用重置方法,您必须首先销毁旧对象(否则该对象可能无法正常运行)。
第二个新是“安置新”。它执行初始化(即调用任何必要的构造函数)而不进行任何分配。当您需要创建自定义内存分配方案时,它很有用。
int * y = new (x) int;
这是根据放置新语法。
编辑:与自定义分配一起,placement new 还有助于重新初始化对象状态,如下所示。
class Test
{
int startVal;
public:
Test()
{
startVal = 1;
}
void setVal(int val) { startVal = val; }
};
int main()
{
Test *p = new Test; //Creates new object and initializes it with
//a call to constructor.
p->setVal(10); //Change object content.
new(p) Test; //Reset object:
//object pointed by p will be re-initialzed here by making
//a call to constructor. startVal will be back to 1
}
如上面评论中所述,对象状态重置也可以使用placement new来实现。Placement new 不分配内存,它在括号中的指定地址构造对象。