指向连续内存的指针

Pointers pointing contiguous memory

本文关键字:指针 内存 连续      更新时间:2023-10-16

考虑以下代码

struct foo
{
    const int txt_len;
    const int num_len;
    char * txt;
    int * num;
    foo(int tl, int nl): txt_len(tl), num_len(nl)
    {
        char * tmp = new char[txt_len * sizeof(char) + num_len * sizeof(int)];
        txt = new (tmp) char [txt_len * sizeof(char)];
        num = new (tmp + txt_len * sizeof(char)) int[num_len * sizeof(int)];
        // is this the same as above?
        // txt = tmp;                                  
        // num = (int *) (tmp + txt_len * sizeof(char));
    }
    ~foo()
    {
        delete[] txt; // is this the right way to free the memory?
    }
};

我希望*txt*num是连续的,这是最好的方法吗?

放置新和指针运算之间有什么区别吗?我应该用哪一个?

如果您想要一个连续的内存块,您必须通过对operator new[]malloc()或类似的调用来将其整体分配。对这些函数的多次调用并不保证所分配块的任何邻接性。你可以分配一大块,然后根据需要从中雕刻零件。

您应该deletefree()所有先前分配有newmalloc()的块,否则您将泄漏内存,并可能使程序不稳定(在某个时刻无法分配更多内存),并对操作系统中的内存施加不必要的压力,可能会减慢其他程序的速度或使其不稳定。

然而,Placementnew实际上并没有分配任何内存。它只是在指定的位置构造一个对象,因此不需要两次释放内存。

我在您的代码中看到的一个问题是它没有对齐int。在某些平台上,从/向内存读取或写入大于1字节的整数必须对齐,否则,您可能会从/向错误的位置读取/写入值,或者导致程序终止的CPU异常。x86在这方面非常宽容,不会介意,尽管可能会因为性能下降而给你带来负担。

由于对齐问题,您需要将int数据放在第一位。但我们不能执行delete num[],因为类型是错误的——在删除之前必须将其强制转换为char*

char * tmp = new char[num_len * sizeof(int) + txt_len * sizeof(char)];
num = new (tmp) int[num_len];
txt = new (tmp + num_len * sizeof(int)) char [txt_len];

(这充分利用了sizeof(char)==1

您可能很想做delete[] num,但num的类型是int*,它是new’ed作为char*。所以你需要这样做;

delete[] (char*) num;

只要使用POD类型,这是相同的。你的删除很好
然而,正如David的评论所说,您需要考虑对齐问题。

Placement-new主要用于在一些预先分配的内存块上调用类/结构的构造函数。

但对于原生类型,使用placement-new&指针算术。

如果我错了,请纠正我。

如果txt和num总是指向int和char、其他内置类型或其他不需要构造的类型,那么不需要。

另一方面,如果要将其中一个更改为需要构造的类,即将txt更改为std::string类型,则需要使用placement-new。

Placementnew允许您调用构造函数,如果您愿意,可以在该地址构建对象。内置类型具有默认构造函数,如果您没有初始化,这些构造函数将不起任何作用。

在这两种情况下,你都需要进行指针运算,只需一种方法将答案存储在指针中,另一种方法是将答案传递给placement new,placement new将其返回给你存储在指针内,然后调用构造函数。