Можно ли использовать unique_ptr с отрицательным индексом без утечки памяти?

Я читаю Разрешены ли отрицательные индексы массива в C? и нашел интересным, что отрицательные значения могут быть использованы для индекса массива. Я попробовал это снова с C ++ 11 unique_ptr и это работает там же! Конечно, средство удаления должно быть заменено чем-то, что может удалить исходный массив. Вот как это выглядит:

#include <iostream>
#include <memory>

int main()
{
const int min = -23; // the smaller valid index
const int max = -21; // the highest valid index
const auto deleter = [min](char* p)
{
delete [](p+min);
};
std::unique_ptr<char[],decltype(deleter)> up(new char[max-min+1] - min, deleter);

// this works as expected
up[-23] = 'h'; up[-22] = 'i'; up[-21] = 0;
std::cout << (up.get()-23) << '\n'; // outputs:hi
}

Мне интересно, есть ли очень, очень маленький шанс, что есть утечка памяти. Адрес памяти созданной в куче (new char[max-min+1]) может переполниться при добавлении 23 к нему и стать нулевым указателем. Вычитание 23 по-прежнему дает исходный адрес массива, но unique_ptr может распознать его как нулевой указатель. unique_ptr не может удалить его, потому что это нуль.

Итак, есть ли вероятность того, что предыдущий код протечет память или умный указатель ведет себя так, что это делает его безопасным?

Примечание: я бы на самом деле не использовал это в реальном коде; Мне просто интересно, как это будет вести себя.

1

Решение

Редактировать: пузырь со льдом В связи с этим возникает интересный момент: в арифметике указателей допустимы только два допустимых значения указателя:

§5.7 [expr.add] p5

Если оба указателя операнд и результат При указании на элементы одного и того же объекта массива или одного элемента после последнего элемента объекта массива оценка не должна вызывать переполнения; в противном случае поведение не определено.

Таким образом, new char[N] - min вашего кода уже вызывает UB.


Теперь на большинстве реализаций это не вызовет проблем. Деструктор std::unique_ptrоднако (предварительно отредактируйте ответ отсюда):

§20.7.1.2.2 [unique.ptr.single.dtor] p2

Эффекты: если get() == nullptr нет никаких эффектов. Иначе get_deleter()(get()),

Так что да, есть вероятность, что вы потеряете память здесь, если она действительно сопоставляется с любым значением, представляющим значение нулевого указателя (скорее всего 0, но не обязательно). И да, я знаю, что это один для отдельных объектов, но массив один ведет себя точно так же:

§20.7.1.3 [unique.ptr.runtime] p2

Описания приведены ниже только для функций-членов, поведение которых отличается от основного шаблона.

И нет описания для деструктора.

4

Другие решения

new char[max-min+1] не выделяет память в стеке, а скорее в куче — вот как это стандартно operator new ведет себя. Выражение max-min+1 оценивается компилятором и приводит к 3таким образом, в конечном итоге это выражение равно выделению 3 байтов в куче. Здесь нет проблем.

Тем не менее, вычитая min приводит к указателю, который на 23 байта превышает начало выделенной памяти, возвращенной new и поскольку в new вы выделили только 3 байта, это определенно будет указывать на местоположение, не принадлежащее вам -> все последующее приведет к неопределенному поведению.

3

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector