14

第二行是什么?(在回答另一个问题时看到。)

int * x = new int [1] ;
int * y = new (x) int;

在第二行之后 x 和 y 具有相同的值(指向同一个地方)。y = x 和第二行有什么区别?它像构造函数还是什么?

4

5 回答 5

13

它的位置新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
于 2010-10-18T15:15:14.213 回答
4

这称为放置新。它允许您在已分配的内存中构造一个对象。

这个较早的线程讨论了它在何处以及如何用于.

于 2010-10-18T15:14:53.683 回答
3

这是新的安置。

尽管您通常不将其与整数类型一起使用。
它通常用于构建缓冲区,然后在其中构建其他类型。

// 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.

请记住,如果您使用重置方法,您必须首先销毁旧对象(否则该对象可能无法正常运行)。

于 2010-10-18T15:46:47.713 回答
3

第二个新是“安置新”。它执行初始化(即调用任何必要的构造函数)而不进行任何分配。当您需要创建自定义内存分配方案时,它很有用。

于 2010-10-18T15:16:08.237 回答
2
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 不分配内存,它在括号中的指定地址构造对象。

于 2010-10-18T15:16:19.923 回答