Переменный размерный C++ структуры

Для добавления и удаления вы можете иметь цикл, который постоянно просит пользователя добавлять и удалять номера и отображать обновленную статистику, например,

.
while True:
    action = int(input("Input -1 if you want to add to the list again. Or -2 if you want to remove from the list"))

    if action == -1:
        print("Enter what you want to be added ")
        add = int(input(""))
        temperatureList.append(add)
        print(temperatureList)
        sm = sum(temperatureList)

        avg = sm / weather

        print("SUM = ", sm)

        print("AVERAGE = ", avg)
    elif action == -2:
        if len(temperatureList) > 1:
            del temperatureList[-1]
            print(temperatureList)
            sm = sum(temperatureList)
            avg = sm / weather
            print("SUM = ", sm)
            print("AVERAGE = ", avg)
        else:
            print("Everything removed from the list")
20
задан unwind 27 March 2009 в 09:28
поделиться

10 ответов

Некоторые мысли о том, что Вы делаете:

  • Используя C-стиль идиома структуры переменной длины позволяет Вам выполнять одно бесплатное выделение хранилища на пакет, который является вдвое меньше, чем требовался бы если struct Packet содержавший a std::vector. Если Вы выделяете очень большое количество пакетов, то выполнение вдвое меньше бесплатных выделений/освобождения хранилища может быть значительным. Если Вы также сделаете доступы к сети, то потраченное ожидание времени сети, вероятно, будет более значительным.

  • Эта структура представляет пакет. Вы планируете к чтению-записи от сокета непосредственно в a struct Packet? Если так, вероятно, необходимо рассмотреть порядок байтов. Вы оказывающийся перед необходимостью преобразовывать от хоста до сетевого порядка байтов при отправке пакетов, и наоборот при получении пакетов? Если так, затем Вы могли подкачка байта данные на месте в Вашей структуре переменной длины. При преобразовании этого для использования вектора, он имел бы смысл к методам записи для сериализации / десериализация пакета. Эти методы передали бы его непрерывному буферу, приняв порядок байтов во внимание.

  • Аналогично, Вы, возможно, должны принять во внимание выравнивание и упаковку.

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

  • Вместо malloc и free, Вы могли использовать Packet* p = ::operator new(size) и ::operator delete(p), с тех пор struct Packet тип POD и в настоящее время не извлекает выгоду из наличия его конструктора по умолчанию и его названного деструктора. (Потенциальное) преимущество выполнения так то, что глобальное operator new ошибки дескрипторов с помощью глобального нового обработчика и/или исключений, если это имеет значение для Вас.

  • Возможно заставить идиому структуры переменной длины работать с новыми и операторами delete, но не хорошо. Вы могли создать пользовательское operator new это берет длину массива путем реализации static void* operator new(size_t size, unsigned int bitlength), но необходимо было бы все еще установить bitlength членскую переменную. Если бы Вы сделали это с конструктором, то Вы могли бы использовать немного избыточное выражение Packet* p = new(len) Packet(len) выделить пакет. Единственное преимущество я вижу по сравнению с использованием глобального operator new и operator delete был бы то, что клиенты Вашего кода могли просто звонить delete p вместо ::operator delete(p). Обертывание выделения/освобождения в отдельных функциях (вместо вызова delete p непосредственно), прекрасен, пока их называют правильно.

10
ответ дан 30 November 2019 в 00:31
поделиться

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

Это осуждено в кругах C++, но я рассматриваю использование его хорошо, если Вы документируете его в коде.

Некоторые комментарии к Вашему коду:

struct Packet
{
    unsigned int bitlength;
    unsigned int data[];
};

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

Packet* CreatePacket(unsigned int length)
{
    Packet *output = (Packet*) malloc((length+1)*sizeof(unsigned int));
    output->bitlength = length;
    return output;
}

Это работает, но Вы не принимаете размер во внимание структуры. Код повредится, после того как Вы добавляете новых участников к своей структуре. Лучше сделайте это этот путь:

Packet* CreatePacket(unsigned int length)
{
    size_t s = sizeof (Packed) - sizeof (Packed.data);
    Packet *output = (Packet*) malloc(s + length * sizeof(unsigned int));
    output->bitlength = length;
    return output;
}

И запишите комментарий в свое определение структуры пакета, что данные должны быть последним участником.

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

К сожалению, C++ не обеспечивает хороший механизм, чтобы сделать это, таким образом, Вы часто заканчиваете с такими взломами malloc/free в приложениях реального мира.

7
ответ дан 30 November 2019 в 00:31
поделиться

Можно использовать "C" метод, если Вы захотите, но для безопасности делают его так, то компилятор не попытается скопировать его:

struct Packet
{
    unsigned int bytelength;
    unsigned int data[];

private:
   // Will cause compiler error if you misuse this struct
   void Packet(const Packet&);
   void operator=(const Packet&);
};
3
ответ дан 30 November 2019 в 00:31
поделиться

Это в порядке (и была общепринятая практика для C).

Но это не хорошая идея для C++.
Это вызвано тем, что компилятор генерирует полный набор других методов автоматически для Вас вокруг класса. Эти методы не понимают, что Вы обманули.

Например:

void copyRHSToLeft(Packet& lhs,Packet& rhs)
{
    lhs = rhs;  // The compiler generated code for assignement kicks in here.
                // Are your objects going to cope correctly??
}


Packet*   a = CreatePacket(3);
Packet*   b = CreatePacket(5);
copyRHSToLeft(*a,*b);

Используйте станд.:: вектор <> это намного более безопасно и работает правильно.
Я также держал бы пари, что это столь же эффективно как Ваша реализация после того, как оптимизатор умирает.

Кроме того, повышение содержит массив фиксированного размера:
http://www.boost.org/doc/libs/1_38_0/doc/html/array.html

5
ответ дан 30 November 2019 в 00:31
поделиться

Если Вы действительно делаете C++, нет никакого практического различия между классом и структурой кроме членской видимости по умолчанию - классы имеют частную видимость по умолчанию, в то время как структуры имеют общедоступную видимость по умолчанию. Следующее эквивалентно:

struct PacketStruct
{
    unsigned int bitlength;
    unsigned int data[];
};
class PacketClass
{
public:
    unsigned int bitlength;
    unsigned int data[];
};

Точка, Вам не нужен CreatePacket (). Можно просто инициализировать объект структуры с конструктором.

struct Packet
{
    unsigned long bytelength;
    unsigned char data[];

    Packet(unsigned long length = 256)  // default constructor replaces CreatePacket()
      : bytelength(length),
        data(new unsigned char[length])
    {
    }

    ~Packet()  // destructor to avoid memory leak
    {
        delete [] data;
    }
};

Несколько вещей отметить. В C++ используйте новый вместо malloc. Я взял некоторую свободу и изменил bitlength на bytelength. Если этот класс представит сетевой пакет, то Вы будете очень более обеспеченным контактом с байтами вместо битов (по-моему). Массив данных является массивом неподписанного символа, интервала весьма со знаком. Снова, это основано на моем предположении, что этот класс представляет сетевой пакет. Конструктор позволяет Вам создавать Пакет как это:

Packet p;  // default packet with 256-byte data array
Packet p(1024);  // packet with 1024-byte data array

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

2
ответ дан 30 November 2019 в 00:31
поделиться

Я, вероятно, просто придерживался бы использования a vector<> если минимальные дополнительные издержки (вероятно, единственное дополнительное слово или указатель по Вашей реализации) действительно не создают проблему. Нет ничего, что говорит, что необходимо изменить размер () вектора, после того как он был создан.

Однако существуют несколько преимущества движения с vector<>:

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

Если Вы действительно хотите препятствовать тому, чтобы массив стал когда-то созданным, Вы могли бы хотеть рассмотреть наличие Вашего собственного класса, который наследовался vector<> конфиденциально или имеет a vector<> участник и только выставляет с помощью методов, которые просто преобразовывают к векторным методам те биты вектора, который Вы хотите, чтобы клиенты смогли использовать. Это должно помочь получить Вас идущий быстро с довольно хорошим обеспечением, которое просачивается и что не не там. Если Вы делаете это и находите, что маленькие издержки вектора не работают на Вас, можно повторно реализовать тот класс без справки вектора, и клиентский код не должен должен быть изменяться.

2
ответ дан 30 November 2019 в 00:31
поделиться

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

К счастью, библиотека повышения сделала большую часть твердой части:

struct packet
{
   boost::uint32_t _size;
   boost::scoped_array<unsigned char> _data;

   packet() : _size(0) {}

       explicit packet(packet boost::uint32_t s) : _size(s), _data(new unsigned char [s]) {}

   explicit packet(const void * const d, boost::uint32_t s) : _size(s), _data(new unsigned char [s])
   {
        std::memcpy(_data, static_cast<const unsigned char * const>(d), _size);
   }
};

typedef boost::shared_ptr<packet> packet_ptr;

packet_ptr build_packet(const void const * data, boost::uint32_t s)
{

    return packet_ptr(new packet(data, s));
}
1
ответ дан 30 November 2019 в 00:31
поделиться

Необходимо объявить указатель, не массив с неуказанной длиной.

0
ответ дан 30 November 2019 в 00:31
поделиться

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

0
ответ дан 30 November 2019 в 00:31
поделиться

Уже существует много хороших мыслей, упомянутых здесь. Но каждый отсутствует. Массивы с переменными границами являются частью C99 и таким образом не являются частью C++, хотя некоторый компилятор C++ может обеспечить эту функциональность нет никакой гарантии этого. Если Вы находите способ использовать их в C++ приемлемым способом, но у Вас есть компилятор, который не поддерживает его, Вы, возможно, можете нейтрализация к "классическому" пути

1
ответ дан 30 November 2019 в 00:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: