Инициализация члена данных структуры C в классе оболочки C ++ - PullRequest
1 голос
/ 09 июля 2011

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

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

/* All of this is in src/liblzma/api/lzma/base.h if you download version 5.0.3
 * XZ Utils
 */
typedef struct {
    const uint8_t *next_in;
    size_t avail_in;
    uint64_t total_in;
    /* ...
     * and so on. Some other members are enums and other structs, but
     * this is basically a POD structure
     */
} lzma_stream;

/* This macro is used to initialize lzma_stream objects */
#define LZMA_STREAM_INIT \
    { NULL, 0, 0, NULL, 0, 0, NULL, NULL, \
    NULL, NULL, NULL, NULL, 0, 0, 0, 0, \
    LZMA_RESERVED_ENUM, LZMA_RESERVED_ENUM }

/* Here's LZMA_RESERVED_ENUM in case anyone's wondering: */
typedef enum {
    LZMA_RESERVED_ENUM = 0
} lzma_reserved_enum;

У меня есть класс-оболочка для lzma_stream, так что если мой код шифрования выбрасывает, деструктор класса-оболочки может вызывать функции, которые освобождают любую назначенную память в lzma_streamструктура.Итак, у меня есть:

class Stream {
public:
    Stream();
    ~Stream();
    void init();
    // ...
private:
    lzma_stream stream_;
    // ...
};

Stream::~Stream() {
    lzma_end( &stream_ );
}

Мой вопрос: как бы вы инициализировали Stream::stream_ и почему?Я мог бы инициализировать членов структуры по отдельности:

Stream::Stream() : stream_(), ... {}

void Stream::init() {
    stream_.next_in = NULL;
    stream_.avail_in = 0;
    // ...
}

Но я бы хотел использовать LZMA_STREAM_INIT, потому что это означало бы, что мне не нужно беспокоиться об изменениях в библиотеке xz.Имея это в виду, в качестве альтернативы, я мог бы создать temp:

Stream::Stream() : stream_(), ... {}

void Stream::init() {
    lzma_stream const temp = LZMA_STREAM_INIT;
    stream_ = temp;
    // ...
}

Предварительный вопрос: есть ли способ, которым я мог бы выполнить инициализацию в Stream ctor (править: я имею в виду, в списке инициализации)?(Я так понимаю, не так ли?) Я стараюсь избегать списков инициализации c ++ 0x, кстати, по соображениям переносимости компилятора.

Как я уже говорил выше, это способы решения проблемы.и это уже было сказано в другом месте;но я хотел бы знать, каким образом вы, ребята, будете это делать (если нет другого способа, о котором я не знаю)?Я уже могу догадаться, что вы бы сказали, что последний метод, но у меня есть хитрое чувство, что есть подвох: есть ли?

ОК, много полезной информации и решений, представленных ниже.Спасибо за помощь, ребята.

Ответы [ 3 ]

2 голосов
/ 09 июля 2011

Да, вы можете использовать ctor-initializer , вам просто нужно добавить вспомогательную функцию:

Stream::Stream() : stream_(def_stream) {}

static lzma_stream def_stream()
{
  lzma_stream tmpStream = LZMA_STREAM_INIT;
  return tmpStream;
}

Помимо прочего, это позволяет вам инициализировать элемент агрегата const,И почти все компиляторы пропустят создание временного.

Если вы столкнетесь с компилятором, который этого не делает, вы можете использовать этот вариант:

static const lzma_stream& def_stream()
{
  static lzma_stream tmpStream = LZMA_STREAM_INIT;
  return tmpStream;
}

В C ++ 0x выВы сможете написать:

Stream::Stream() : stream_ LZMA_STREAM_INIT {}

, который использует "единый синтаксис инициализатора".

0 голосов
/ 09 июля 2011

Почему бы просто не поставить инициализацию в ctor?

Stream::Stream() : ...
{
    lzma_stream const temp = LZMA_STREAM_INIT;
    stream_ = temp;
    // ...
}

Обратите внимание, что вам не нужен mem-инициализатор для stream_. Когда член POD не имеет инициализатора mem, C ++ оставляет его «неинициализированным», как локальная переменная lzma_stream stream;. Но если вы сразу назначаете это, это не так уж и плохо.

Я также отмечаю, что lzma сама рекомендует этот шаблон временного назначения объекта (в base.h) для случаев, когда прямая инициализация не может быть выполнена. В C речь идет больше о том, когда память lzma_stream была malloc -ed, но это также относится к членам класса C ++ 03. (C ++ 0x имеет способ сделать это в mem-инициализаторе, да.)

0 голосов
/ 09 июля 2011

Конечно, вы могли бы:

Stream::Stream() : your_init_list {
    lzma_stream tmpStream = LZMA_STREAM_INIT;
    stream_ = tmpStream;
}

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

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

Edit # 2: Как указывает Бен, вы можете использовать вспомогательную функцию для этого, но прямая инициализация поля в списке инициализации (что-то вроде stream_(LZMA_STREAM_INIT)) невозможна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...