Больше контроля над созданием объектов-членов в C ++ - PullRequest
3 голосов
/ 17 февраля 2012

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

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

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

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

Каков наилучший способ сделать это?

Редактировать

Я заметил вопрос " Можно ли отложить инициализацию члена конструктораbody?", который рекомендовал boost :: необязательный.Это не решило мою проблему по нескольким причинам.Во-первых, я не хочу откладывать инициализацию, просто имею больше контроля над ней.Во-вторых, boost :: option хранит дополнительный bool, указывающий, инициализирован ли объект, что в моем случае не требуется.Это, однако, заставило меня задуматься, и я нашел решение, которое я разместил ниже.

Ответы [ 3 ]

4 голосов
/ 17 февраля 2012

Вы не можете "повторить" конструкцию только через конструктор.Вы можете проглотить / обработать исключение, вызванное в вашем конструкторе, используя try / catch, и продолжать заполнять объект, если код внутри конструктора завершится неудачно (с помощью простых назначений).

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

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

Двигаемся дальше ... когда вы вызываете конструктор, вы вызываете конструктор.Сам конструктор создает объект в куче или в стеке в зависимости от того, использовали ли вы механизмы динамического выделения (в основном, новые).Вы не можете решить внутри самого конструктора объявить объект где-то еще, решение уже принято.Чтобы добиться этого, вам придется напрямую использовать новое место размещения при вызове нового.

0 голосов
/ 21 февраля 2012

Я закончил тем, что создал следующий класс:

#include <type_traits> // Or <boost/type_traits.hpp>
template <typename Ty>
class manually_constructed
{
public:
   template <typename T>
   manually_constructed(T construct_func) {
      construct_func(static_cast<Ty*>(static_cast<void*>(&data)));
   }
   ~manually_constructed() {
      static_cast<Ty*>(static_cast<void*>(&data))->~Ty();
   }
   Ty& operator*() {
      return *static_cast<Ty*>(static_cast<void*>(&data));
   }
   Ty* operator->() {
      return static_cast<Ty*>(static_cast<void*>(&data));
   }
private:
   // Replace 'std' with 'boost' if your standard library doesn't support
   // type_traits, yet.
   std::aligned_storage<sizeof(Ty), std::alignment_of<Ty>::value>::type data;
};

Тогда в моем классе я могу иметь член, такой как manually_constructed<OtherClass> object, и закрытый статический метод, такой как:

static void construct_object(OtherClass *p) {
   try {
      new(p) OtherClass(/* Risky arguments */);
   } catch(...) {
      new(p) OtherClass(/* Fallback arguments */);
   }
}

Наконец, в моем списке инициализатора у меня может быть object(construct_object).

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

0 голосов
/ 17 февраля 2012

Разобрать процедуру построения и инициализации.Я знаю, что это может звучать странно для вас, но сделайте конструкцию базового объекта в списке инициализации, а затем попытайтесь / поймайте, чтобы инициализировать его в теле конструктора с различными наборами параметров с помощью отдельного метода init ().

...