Структура для ввода параметров, передаваемых в наборе функций - PullRequest
0 голосов
/ 29 марта 2011

Мне нужна гибкость, чтобы иметь возможность изменять параметры, передаваемые различным функциям, в зависимости от того, где произошел вызов функции, поэтому я решил поместить все свои параметры в структуру, однако большинство этих параметров являются структурами или сами классы, и я хочу иметь возможность оставить их NULL, поэтому я должен передавать указатели на структуры / классы.

struct A
{
    otherB* b;  // NULL should be a valid value
    otherC* c;
};

Однако мой вопрос сейчас заключается в том, что передача A вокруг этих указателей будет единственной копией, поэтому, если я сделаю следующее, возникнет проблема, верно?

void func(A& a) //non const cause I wanna change contents of A.
{
   a.b = new b();
}

A myA;
otherC somec; // all these are currently automatic variables in my pgm.
myA.c = &somec;

func(myA);  //myA goes out of scope? so I've lost all pointers assigned and since somec is out of scope too, I have a problem?

Как лучше всего разрешить что-то подобное? + Мне нужна гибкость, позволяющая передавать NULL любому из моих параметров, но не уверен, что использование сырых указателей везде - хорошая идея?

Ответы [ 5 ]

4 голосов
/ 29 марта 2011

Чтобы решить проблему управления ресурсами, вы должны использовать boost::shared_ptr (или std::shared_ptr в C ++ 0x).

struct A
{
    boost::shared_ptr< otherB > b;
    boost::shared_ptr< otherC > c;
};

void func(A& a)
{
   a.b = boost::make_shared< otherB >();
}

A myA;
otherC somec;
myA.c = boost::shared_ptr< otherC >(&somec, null_deleter());

func(myA);

Когда myA выходит из области видимости, все ресурсы освобождаются автоматически. Поскольку somec было выделено в стеке, мы обернули его в shared_ptr, который использует null_deleter, который может выглядеть следующим образом:

struct null_deleter {
    void operator()(void *) { }
};

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

1 голос
/ 29 марта 2011

boost::optional<> Позволяет проверить, установлено поле или нет.

Простой пример (не скомпилируется, я даже не тестировал удаленно, теоретически так оно и должно работать)

struct params
{
  boost::optional<int> a;
  boost::optional<foo> b;
  boost::optional<bar> c;
};

void func(params& p)
{
  if (p.a)
  {
    // do stuff with a
  }
  if (p.b)
  {
    // do stuff with b
  }
  if (p.c)
  { 
    // do stuff with c
  }
  else
    p.c = bar(); // again copy constructed and now initialized...
}

params p;
p.a = 1;
p.b = foo(); // copy constructed, however you can store a reference in the optional too.
// c is uninitialized

func(p);

// when p goes out of scope, everything is gone..
0 голосов
/ 29 марта 2011

Это не ясно из вашего описания, но если у вас возникла проблема, потому что кто-то выходит из области видимости, это может быть только потому, что func сохраняет копию указателя.Не делайте этого: в функции скопируйте объект, а не указатель.

PS: если большинство указателей в большинстве случаев являются нулевыми, вам следует рассмотреть возможность использования чего-то вроде следующего синтаксического сахара:

struct A
{
    //  pointer members...
    A() : // ... set all pointers to null...
    A& withB( B const& someB ) { otherB = &someB; return *this ; }
    A& withC( C const& someC ) { otherC = &someC; return *this ; }
    //  And so on for all of the rest of the pointers.
};

func( A().withC( somec ) );

Не знаю, подходит ли это для вашей ситуации, но часто это удобно.

0 голосов
/ 29 марта 2011

Нет, ваше представление о сфере действия myA и somec неверно.Нет ничего плохого в том, что у вас есть сейчас, хотя я лично считаю, что ссылки будут лучшим вариантом для указателей.

0 голосов
/ 29 марта 2011

В основном вам нужно проанализировать владение , т. Е. Кто может выделять и кто отвечает за удаление объекта, если он больше не используется.

Важно помнить одну вещь: если вы смешиваете динамически размещенные вещи и вещи, помещенные в стек, вы просто не можете применить delete к ним, так как невозможно удалить вещи в стеке.

Одним из способов может быть только использование new и определение деструктора в A, который удаляет все его указатели. Другим способом может быть место, где вы будете регистрировать объекты, которые впоследствии должны быть удалены. Или вы можете пойти по пути использования существующих инструментов подсчета ссылок, как это предлагается в других ответах.

...