LINUX.ORG.RU

Уперся в проблему с С++.

 


0

1

Подскажите пожалуйста правильный паттерн в данной ситуации. Есть некая АПИ функция возвращающая указатель на структуру содержащую информацию о системном ресурсе (Win32 на самом деле, но не суть), и есть парная ей функция очищающая данную структуру и освобождающая видимо как то системный ресурс. Так вот я налабал обертку облегчающую мне работу с данной структурой в ООП стиле. В конструкторе передаю указатель на структуру, в деструкторе вызываю системную функцию очищения и передаю ей сохраненную в поле данных копию указателя. Причем если я создаю два экземпляра класса оборачивающих одну и ту же структуру(напомню указатель мне возвращает системная функция), естественно у меня два раза вызывается функция очищения и в программе происходит исключение. Внимание вопрос: как сделать правильно?

★★

1. передавай не указатель на структуру, а идентификатор

2. используй счетчик ссылок

vvviperrr ★★★★★ ()

Ну добавь счётчик использования. Почитай как сделан shared_ptr.

navrocky ()

в данном случае тебе просто необходим Паттерн Singleton

а счетчики будут адским костылем

Deleted ()
Ответ на: комментарий от Deleted

Синглтоны живут до завершения программы, из его поста не ясно нужно ли это ему или нет.
А счетчики вполне себе типичное решение в данной ситуации.

anonymous ()

Причем если я создаю два экземпляра класса оборачивающих одну и ту же структуру(напомню указатель мне возвращает системная функция)

А что системная функция возвращает всегда один и тот же указатель? Тогда нафига его освобождать - утечки ресурсов все равно не будет, т.к. ресурс всего один.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

Он сумбурно как-то написал, может он один раз получает указатель и дважды его оборачивает.

anonymous ()

Глянь на boost/intrusive_ptr наваяй что-то подобное и
заверни свою штуку в него -)

Boy_from_Jungle ★★★★ ()
Ответ на: комментарий от no-such-file

Нет разные функция возвращает. просто я создавал два объекта. Теперь обернул в shared_ptr и сделал проверку на unique чтобы функция очистки вызывалась если несколько оберток оборачивают одну и ту же структуру.

mio ★★ ()
Последнее исправление: mio (всего исправлений: 1)
Ответ на: комментарий от no-such-file

И сделал в шаред поинтере пустой делетер. потому что для очистки используется системная функция и просто вызывать delete нельзя

mio ★★ ()
Ответ на: комментарий от anonymous

А почему не хранить указатель на ту структуру в shared_ptr'е внутри обертки

Так и сделал

mio ★★ ()

запрятать структуру с указателем в классе, получать только в классе, чистить там же.

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

класс возвращает тебе необходимую информацию для обьекта в понятном для других обьектов виде.

invy ★★★★★ ()

Есть некая АПИ функция возвращающая указатель на структуру содержащую информацию о системном ресурсе

Может эту функцию только в конструкторе и вызывать? Тогда два экземпляра на одну структуру и не будут ссылаться.

ratatosk ()
Ответ на: комментарий от anonymous

А почему не хранить указатель на ту структуру в shared_ptr'е внутри обертки?

Если два shared_ptr будут инициализированы одним и тем же указателем, double delete не миновать. Этого изменения не достаточно.

Лучше уж хранить ее в shared_ptr и СНАРУЖИ обертки, передав в shared_ptr deleter, вызывающий ф-цию зачистки.

ratatosk ()

Singleton (но это больше для объектов живущих весь рантайм) или shared_ptr.

UPD: тред не читай, сразу флуди :D

erfea ★★★★★ ()
Последнее исправление: erfea (всего исправлений: 1)

shared_ptr со своим deleter'ом. В бусте такое точно можно сделать, в 11 стандарте, думаю, тоже.

kulti ★★ ()
Ответ на: комментарий от nanoolinux

что-то типа такого

class Device
{
	public:
		Device(const DevIdent &di)
			:s_(std::unique_ptr <SuperPuperStruct> (::struct_open(di.toRawIdent()), ::struct_close) {}
		//iface here
	private:
		std::unique_ptr <SuperPuperStruct> s_;
};

typedef std::shared_ptr <Device> pDevice;

pDevice device_factory(const DevIdent &di) {
	return std::make_shared <Device> (di);
}

nanoolinux ★★★★ ()
Ответ на: комментарий от nanoolinux

Вот только фабричной функции лучше возвращать std::unique_ptr, он может быть при необходимости преобразован в std::shared_ptr.

Begemoth ★★★★★ ()

Загляни в исходники MFC, связанные, например, с GDI.
В конструкторе либо (для шрифта) в CreateFont() или CreateFontIndirect() занимаем ресурс, потом либо сами освобождаем, дёргая за DeleteObject() базового класса CGdiObject либо это делает деструктор ~CGdiObject() А согласно принципам ООП вся кухня с системными вызовами и структурой должна быть скрыта этим классом.

Uter ()
Последнее исправление: Uter (всего исправлений: 1)
Ответ на: комментарий от mio

Нет разные функция возвращает. просто я создавал два объекта

Если функция возвращает разные указатели, как ты создал два одинаковых объекта?

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

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

mio ★★ ()
Ответ на: комментарий от no-such-file

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

mio ★★ ()
Ответ на: комментарий от mio

что-то недоглядел оборачиваю одну и ту же структуру в два своих объекта

Я правильно понял, что ты получаешь эту структуру не в конструкторе, а заранее и передаешь конструктору как параметр? Тогда это эталонное ССЗБ.

no-such-file ★★★★★ ()
Ответ на: комментарий от mio

Структура должна освобождаться на том же уровне вложенности кода, на котором выделялась. Освобождать структуру в деструкторах порождённых этим уровнем объектов - идеологически неправильно. Нужно где-то так:

  allocStruc(s);
  ...
  obj1 = new Something(s);
  obj2 = new Something(s);
  ...
  delete obj1;
  delete obj2;
  ...
  freeStruc(s);

Счётчик ссылок и прочее которое предлагают некоторые - не панацея, поскольку не гарантирует обращения к струкуре после того как счётчик обнулится и её ресурсы будут освобождены.

auto12884835 ()
Ответ на: комментарий от auto12884835

не гарантирует обращения к струкуре после того как счётчик обнулится и её ресурсы будут освобождены.

Что я только что прочитал?

anonymous ()
Ответ на: комментарий от no-such-file

Ручной delete?

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

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

Таким способом, которым это пытается делать ТС, наверное незачем. Я бы ещё понял, если бы ресурс выделялся в конструкторе, а освобождался в деструкторе того же самого класса. А так - ну может ему за количество строк платят, ты же не знаешь.

auto12884835 ()
Ответ на: комментарий от auto12884835

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

Проблема в том, что в крестах данный код не имеет линейности в принципе т.к. между new и delete может произойти исключение и возникнет утечка ресурса.

Я бы ещё понял, если бы ресурс выделялся в конструкторе, а освобождался в деструкторе того же самого класса

Вот и я о том же. Мне показалось, что ТС просто не врубается, что он делает не так.

no-such-file ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.