Указатели, указывающие на непрерывную память - PullRequest
1 голос
/ 07 января 2012

Рассмотрим следующий код

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 были смежными, это лучший способ сделать это?

и есть ли разница междуразмещение нового и указатель арифметики?какой я должен использовать?

Ответы [ 5 ]

1 голос
/ 07 января 2012

Сначала вам нужно будет поместить данные 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 'обозначен как char*.Так что вам нужно сделать;

delete[] (char*) num;
1 голос
/ 07 января 2012

Если вы хотите непрерывный блок памяти, вы должны выделить его целиком с помощью одного вызова operator new[] или malloc() или подобного. Многократные вызовы этих функций не гарантируют какого-либо смежности выделенных блоков. Вы можете выделить большой блок, а затем вырезать из него части по мере необходимости.

И вам следует delete и free() все блоки, ранее выделенные с помощью new и malloc(), иначе вы потеряете память и, вероятно, сделаете вашу программу нестабильной (в какой-то момент она не сможет выделить больше памяти) и оказывать ненужное давление на память в ОС, возможно, замедляя работу других программ или делая их нестабильными.

Размещение нового, однако, фактически не выделяет никакой памяти. Он просто создает объект в указанном месте, поэтому вам не нужно освобождать эту память дважды.

Одна проблема, которую я вижу в вашем коде, заключается в том, что он не выравнивает целые числа. На некоторых платформах чтение или запись целых чисел, превышающих 1 байт, из / в память должны быть выровнены, и если это не так, вы можете либо читать / записывать значения из / в неправильные места, либо получать исключения CPU, приводящие к завершению вашей программы. В этом отношении x86 очень требователен и не будет возражать, хотя может обременять вас ухудшением производительности.

0 голосов
/ 07 января 2012

Если txt и num всегда указывают на int и char, другие встроенные типы или другие типы, не требующие построения, то no. Вам не нужно размещать новое.

Если, с другой стороны, вам нужно изменить один из них на класс, требующий построения, то есть изменить txt на тип std :: string, тогда необходимо использовать размещение new.

Placement new позволяет вам вызывать конструктор, строя, если хотите, объект по этому адресу. Встроенные типы имеют конструкторы по умолчанию, которые ничего не делают, если вы не инициализируете.

В обоих случаях вам нужно сделать арифметику с указателями, просто одним способом вы сохраняете ответ в указателе, другим вы передаете ответ на новое место размещения, которое возвращает его для хранения в указателе, а затем вызывает конструктор .

0 голосов
/ 07 января 2012

Размещение new чаще всего используется, когда вы хотите вызвать конструктор класса / структуры в некоторых предварительно выделенных блоках памяти.

Но для нативных типов использование новой и указательной арифметики не отличается.

Пожалуйста, поправьте меня, если я был неправ.

0 голосов
/ 07 января 2012

Это то же самое, что и при использовании типов POD.И ваше удаление в порядке.
Однако, как говорится в комментарии Дэвида, вам нужно рассмотреть проблемы с выравниванием.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...