Как я узнаю, что объект выделен в куче, используя new? - PullRequest
1 голос
/ 01 января 2012

Я хочу знать, существует ли какая-либо стандартная библиотечная функция или другой прием, с помощью которого я могу запросить, назначен ли указатель приложением.На самом деле я хочу сделать следующее ....

Предположим, у меня есть функция:

void DoSomeThing(SomeObject* pObj);

Теперь для вызова этой функции у нас обычно есть два варианта:

//The first method using stack

SomeObject ObjLocal(Arg1,Arg2);
DoSomething(&ObjLocal);

//The second method using heap

SomeObject* ObjUserAllocated=new SomeObj(Arg1,Arg2);
DoSomeThing(ObjUserAllocated);

//But I like to use code like below (saves me some typing)

DoSomeThing(new SomeObject(Arg1,Arg2));

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

Я разместил этот вопрос здесь, даже не пытаясь найти его в Google, потому что мне так любопытно, и если я получу чистое решение, которое будет для меня большой наградой ... очень жаль.

Если невозможно определить, находится ли объект в куче, как вы, гуру, предложите мне реализовать то, что я хочу?

Ответы [ 3 ]

11 голосов
/ 01 января 2012

Нет никакого портативного способа определить, относится ли указатель к объекту с динамическим размещением, нет.

Это «избавляет меня от необходимости печатать» - очень плохая причина, чтобы выбрать одно решение проблемы вместо другого.,Из трех представленных вами вариантов первый, безусловно, является наилучшим, поскольку он опирается на автоматическое управление временем жизни.

При этом, если вы действительно создаете объект просто для передачи функции DoSomeThing, лучшимопция, скорее всего, DoSomeThing принимает SomeObject по значению (или по const-ссылке);тогда вам вообще не нужно иметь дело с указателями.

3 голосов
/ 01 января 2012

как узнать, выделен ли объект в куче с помощью new или malloc () текущим модулем?

Вы не можете.Учитывая только значение указателя, не существует переносимого / надежного способа определить, было ли оно выделено new, malloc() или даже указывает на что-либо в бесплатном хранилище (как показывает ваш первый метод, указатель переданможет фактически указывать на объект на автоматическом хранении).Это может даже указывать на элемент в массиве.DoSomeThing() не может сказать, что это невозможно.

Чтобы справиться с этим, пользователи вашей функции должны сами управлять памятью.Первый метод - это то, что обычно делается для чего-то подобного, так как распределение стека происходит автоматически.Например, большая часть Windows API (которая по большей части является C API) сделана так, как ваш первый метод:

WNDCLASSEX wndcls;
// Fill wndcls structure
::RegisterClassEx(&wndcls);

Здесь RegisterClassEx() не волнует, если мойWNDCLASSEX находится в стеке, в бесплатном хранилище или как часть массива, пока я передаю указатель, который фактически указывает на WNDCLASSEX.Таким образом, ваш первый метод действительно является предпочтительным способом работы с ним в реальной практике.


Если поддержка C не требуется, вы также можете использовать ссылки:

void DoSomeThing(SomeObject& out) {}

Преимущество этого подхода заключается в том, что пользователи не могут передавать указатель NULL, поэтому вам не нужно проверять его.Если DoSomeThing() не изменяет SomeObject, то еще лучше использовать ссылки const:

void DoSomeThing(const SomeObject& out) {}

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

DoSomeThing(SomeObject(Arg1,Arg2));

Таким образом, вы получаете "меньше печатать", что вам нужно, не беспокоясь об управлении памятью.

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

Прежде всего позвольте мне сказать, что вы почти наверняка создаете что-то плохое, чтобы столкнуться с этой ситуацией.

Тем не менее, вы можете сделать это с некоторыми shared_ptr злоупотребления:

void DoSomeThing(std::shared_ptr<SomeObject> pObj);

SomeObject obj(arg1, arg2);

DoSomeThing(new SomeObject(arg1, arg2));
DoSomeThing(std::shared_ptr<SomeObject>(&obj, [](SomeObject*){})); // Empty deleter written as C++11 lambda (could write out the functor elsewhere if not using C++11)
...