Russian Qt Forum
Ноябрь 15, 2024, 14:41 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Трудности с подсчетом байтов памяти занимаемыми экземпляром класса.  (Прочитано 2791 раз)
Eten
Гость
« : Апрель 21, 2013, 15:44 »

Всем привет и доброго здравия.  Подмигивающий

Когда замерял с помощью sizeof свой класс, который хочется сжать по короче, то заметил, что с 40 байт получилось только 28 байт, переведя числовые переменные в указатели и строковые также. Булевная переменная занимает 1 байт, указатель 4 байта, перечисление тоже 4 байта.

Посчитал вручную получается 18 байтов (с учетом от базовых). А откуда 10 байтов выросли никак не пойму.

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

Народ, можете просветить меня в том, что упустил из внимания? Что влияет на кол-во памяти, кроме переменных хранящихся внутри класса и являющихся его членами?!

З.Ы.
Разумеется сам класс вместе с его базовыми выкладываю ниже.

Классы, которые для него базовые:
Код:
#include <QString>

enum RFGroupDataTypes {
    eRFSimpleDataTypes,
    eRFArea
};

class IRFDataTypes
{
public:
    virtual ~IRFDataTypes() { }

    virtual qint32 id() const = 0;
    virtual void setId(qint32 id) = 0;
    virtual QString name() const = 0;
    virtual void setName(QString name) = 0;

    virtual RFGroupDataTypes groupDataTypes() const = 0;

protected:
    //если идентификатор равен -1, значит это либо временная переменная, либо константное значение
    qint32 *_id;
    //константные или временные значения имен не имеют, только переменные.
    QString *_name;
    //указание на принадлежность к группе типов данных.
    RFGroupDataTypes _groupdatatypes;
};

//Интерфейс простых типов данных
class IRFSimpleDataTypes : public IRFDataTypes
{
public:
    virtual QString valueToQString() const = 0;

protected:
    //это указывает на константное значение
    bool _constValue;
};

class RFSimpleDataTypes : public IRFSimpleDataTypes
{
public:
    RFSimpleDataTypes()
    {
        _id = new qint32(-1); _name = new QString("");
        _constValue = false;
        _groupdatatypes = eRFSimpleDataTypes;
    }

    qint32 id() const {return *_id;}
    void setId(qint32 id) {*_id = id;}
    QString name() const {return *_name;}
    void setName(QString name) {if (name != NULL) *_name = name; else *_name = "";}

    RFGroupDataTypes groupDataTypes() const {return _groupdatatypes;}

    bool constValue() const {return _constValue;}
    void setConstValue(bool constValue) {_constValue = constValue;}
};


Сам класс:
Код:
#include <limits>
#include <cmath>
#include <time.h>



//Основа Чисел (или просто Числовой)
class RFNumeric : public RFSimpleDataTypes
{
public:

    RFNumeric(double value = 0)
        : RFSimpleDataTypes()
    {
        _isTypeInteger = false;

        _value = new double;

        setValue(value);

    }

    RFNumeric(double value, bool isTypeInteger)
            : RFSimpleDataTypes()
    {
        setisTypeInteger(isTypeInteger);

        _value = new double;

        setValue(value);
    }


    QString valueToQString() const
    {
       int decpt, sign;

       QString s(fcvt(*_value, 18, &decpt, &sign));

       if (decpt > 0 && *_value < 0.0 ? *_value - ceil(*_value) : *_value - floor(*_value) == 0.0)
       {//здесь число без цифр отличных от нуля после десятичной запятой
           s.remove(decpt, s.length() - decpt);
       }
       else
       {//наоборот
           if (decpt > 0)
                s = s.insert(decpt,'.');
           else
           {
                QString s2 = "0.";
                for (int i = 0; i < decpt * (-1); i++) s2 += '0';
                s.insert(0, s2);
           }

           bool isNumberNull = true;

           while(isNumberNull)
           {
               if (s[s.length() - 1] == '0')
               {
                   s.remove(s.length() - 1, 1);
                   isNumberNull = true;
               }
               else
               {
                   isNumberNull = false;
               }
           }
       }

       //после преобразования числа в строку, проверяем его на отрицательность
       if (sign != 0)
            s = s.insert(0, '-');

       return s;
    }



    //целочисленное деление
    static RFNumeric rfnDiv(RFNumeric a, RFNumeric b)
    {
        return RFNumeric(ldiv(qint32(a), qint32(b)).quot, true);
    }

    //% (остаток от целочисленного деления)
    static RFNumeric rfnMod(RFNumeric a, RFNumeric b)
    {
        return RFNumeric(ldiv(qint32(a), qint32(b)).rem, true);
    }

    //возведение в степень
    static RFNumeric rfnPow(RFNumeric a, RFNumeric b)
    {
        return RFNumeric(pow(double(a), double(b)), a.isTypeInteger() && b.isTypeInteger());
    }

    //квадратный корень
    static RFNumeric rfnSqrt(RFNumeric a)
    {
        return RFNumeric(sqrt(double(a)), a.isTypeInteger());
    }

    //модуль числа
    static RFNumeric rfnAbs(RFNumeric a)
    {
        return RFNumeric(std::abs(double(a)), a.isTypeInteger());
    }

    //минимальное число
    static RFNumeric rfnMin(RFNumeric a, RFNumeric b)
    {
        double d1 = double(a), d2 = double(b);
        return d1 < d2 ? RFNumeric(d1, a.isTypeInteger()) : RFNumeric(d2, b.isTypeInteger());
    }

    //максимальное число
    static RFNumeric rfnMax(RFNumeric a, RFNumeric b)
    {
        double d1 = double(a), d2 = double(b);
        return d1 > d2 ? RFNumeric(d1, a.isTypeInteger()) : RFNumeric(d2, b.isTypeInteger());
    }

    //десятичный логарифм
    static RFNumeric rfnLog10(RFNumeric a)
    {
        return RFNumeric(log10(double(a)));
    }

    //натуральный логарифм
    static RFNumeric rfnLog(RFNumeric a)
    {
        return RFNumeric(log(double(a)));
    }

    //экспонента в степени "a"
    static RFNumeric rfnExp(RFNumeric a)
    {
        return RFNumeric(exp(double(a)));
    }

    //косинус
    static RFNumeric rfnCos(RFNumeric a)
    {
        return RFNumeric(cos(double(a)));
    }

    //синус
    static RFNumeric rfnSin(RFNumeric a)
    {
        return RFNumeric(sin(double(a)));
    }

    //тангенс
    static RFNumeric rfnTan(RFNumeric a)
    {
        return RFNumeric(tan(double(a)));
    }

    //арктангенс
    static RFNumeric rfnCtan(RFNumeric a)
    {
        return RFNumeric(1.0 / tan(double(a)));
    }

    //арккосинус
    static RFNumeric rfnACos(RFNumeric a)
    {
        return RFNumeric(acos(double(a)));
    }

    //арксинус
    static RFNumeric rfnASin(RFNumeric a)
    {
        return RFNumeric(asin(double(a)));
    }

    //арктангенс
    static RFNumeric rfnATan(RFNumeric a)
    {
        return RFNumeric(atan(double(a)));
    }

    //арккатангенс
    static RFNumeric rfnACtan(RFNumeric a)
    {
        return RFNumeric(1.0 / atan(double(a)));
    }

    //округление в сторону нуля до целого
    static RFNumeric rfnFloor(RFNumeric a)
    {
        return RFNumeric(floor(double(a)));
    }

    //округление в большую сторону до целого
    static RFNumeric rfnCeil(RFNumeric a)
    {
        return RFNumeric(ceil(double(a)));
    }

    //округление до целого
    static RFNumeric rfnRound(RFNumeric a)
    {
        return RFNumeric(floor(double(a) + 0.5));
    }

    //выделение дробной части
    static RFNumeric rfnFractional(RFNumeric a)
    {
        double d = double(a);
        return d < 0.0 ? RFNumeric(d - ceil(d)) : RFNumeric(d - floor(d));
    }

    //отсечение дробной части
    static RFNumeric rfnInteger(RFNumeric a)
    {
        double d = double(a);
        return d < 0.0 ? RFNumeric(ceil(d)) : RFNumeric(floor(d));
    }

    //целочисленный рандом от 0 и до a-1
    static RFNumeric rfnRandom(RFNumeric a)
    {
        srand ( time(NULL) );
        return RFNumeric(rand() % qint32(a), false);
    }

    //рандом от 0 до 1
    static RFNumeric rfnRnd()
    {
        srand ( time(NULL) );
        return RFNumeric(double(rand() % 1001)/1000.0);
    }


    RFNumeric operator+(RFNumeric b)
    {
        return RFNumeric(this->value() + b.value(), this->isTypeInteger() && b.isTypeInteger());
    }

    RFNumeric operator-(RFNumeric b)
    {
        return RFNumeric(this->value() - b.value(), this->isTypeInteger() && b.isTypeInteger());
    }

    RFNumeric operator*(RFNumeric b)
    {
        return RFNumeric(this->value() * b.value(), this->isTypeInteger() && b.isTypeInteger());
    }

    RFNumeric operator/(RFNumeric b)
    {
        return RFNumeric(this->value() / b.value(), this->isTypeInteger() && b.isTypeInteger());
    }

    void operator++(int)
    {
        if (isTypeInteger())
            *_value = checkingInt32Borders(*_value + 1);
        else
            *_value = checkingFloatBorders(*_value + 1);
    }

    void operator--(int)
    {
        if (isTypeInteger())
            *_value = checkingInt32Borders(*_value - 1);
        else
            *_value = checkingFloatBorders(*_value - 1);
    }

    bool operator==(RFNumeric b)
    {
        return this->value() == double(b);
    }

    bool operator!=(RFNumeric b)
    {
        return this->value() != double(b);
    }

    bool operator<=(RFNumeric b)
    {
        return this->value() <= double(b);
    }

    bool operator>=(RFNumeric b)
    {
        return this->value() >= double(b);
    }

    bool operator<(RFNumeric b)
    {
        return this->value() < double(b);
    }

    bool operator>(RFNumeric b)
    {
        return this->value() > double(b);
    }

    operator QString() {return valueToQString();}

    operator double() {return checkingFloatBorders(value());}

    operator qint32() {return checkingInt32Borders(*_value);}

    //оператор ниже позволяет передать указателю значения из экземпляра класса
    operator RFNumeric*()
    {
        RFNumeric* prfn = new RFNumeric();

        prfn->setId(id());
        prfn->setConstValue(constValue());
        prfn->setName(name());
        prfn->setisTypeInteger(isTypeInteger());
        prfn->setValue(value());

        return prfn;
    }


private:

    long double int32Max() const {return 2147483647;}

    long double int32Min() const {return -2147483647;}

    long double floatMax() const {return 2.147483647e9;}

    long double floatMin() const {return 2.147483647e-9;}

    double checkingFloatBorders (double value) const
    {
        //В этой функции +/-inf приравниваются к max и min границам.
        double d = fabs(value);
        bool usign = value >= 0.0;

        if (d >= floatMax())
            return (usign) ? floatMax() : -floatMax();

        if (d <= floatMin() && d > 0.0)
            return (usign) ? floatMin() : -floatMin();

        return value;
    }

    qint32 checkingInt32Borders(double value) const
    {
        if (value >= int32Max()) return int32Max();

        if (value <= int32Min()) return int32Min();

        return qint32(value);
    }


    void setisTypeInteger(bool isTypeInteger) {_isTypeInteger = isTypeInteger;}

    //Если истинно, то значение принимается и выдается (при печати числа на экране)
    // с отсечение дробной части числа и соблюдением границ типа qint32.
    bool isTypeInteger() const {return _isTypeInteger;}

    void setValue(double value)
    {
        if (isTypeInteger())
            value = checkingInt32Borders(value);
        else
            value = checkingFloatBorders(value);

        *_value = value;
    }

    double value() const {return checkingFloatBorders(*_value);}

    double *_value;

    bool _isTypeInteger;
};

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Апрель 21, 2013, 16:48 »

Во-первых
Цитировать
Размер структуры НЕ равен сумме размеров всех ее членов.
Есть выравнивание (alignment) для членов. Напр адрес члена типа int будет равняться на 4 (если align 4 и выше)

Во-вторых, если есть хоть 1 virtual добавляется "указатель на VMT" - как бы личные данные копилятора используемые для вызова виртуальных методов.
Записан
Bepec
Гость
« Ответ #2 : Апрель 21, 2013, 16:56 »

И добавим гениальную систему умных хранилищ Qt. Где любая строка лишь указатель на место хранения структуры (неточная информация, либо информация описанная не теми словами, см. PS). А если добавляем пару ваших указателей, то  размер вашего класса sizeOf неподвластен Веселый

PS точно не помню, но когда то пытался узнать сколько занимает QString Веселый Оказалось всегда 4 байта Веселый А вот если получить указатель на char, то намного больше.

PPS чтоб получить полный размер вашего класса, нужно тогда пройтись по всем членам класса, имеющим указатели (или являющиеся указателями), сложить размер их объектов (так же возможна ситуация аля указатель на указатель на указатель Веселый ) и добавить размер вашего класса.
« Последнее редактирование: Апрель 21, 2013, 17:00 от Bepec » Записан
Eten
Гость
« Ответ #3 : Апрель 21, 2013, 20:15 »

Хм, спасибо. Видимо, пока не по зубам мне это. Будем расти, может позднее получится.  Подмигивающий
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.139 секунд. Запросов: 22.