Тратим место впустую, или почему sizeof(T) вседа != 0
От: _Winnie Россия C++.freerun
Дата: 16.02.04 11:01
Оценка:
Для чего проектировщики С++ постановили, что тип не может быть нулего размера?
Столько места впустую пропадает!
Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.


Вот, например, этот код у меня выводит значение "56"!!!
А с #pragma pack(1) — "41"!!!

template <int i>
struct X {};

template <class T1,class T2,class T3,class T4,class T5>
struct C1: T1, T2, T3, T4, T5 
{
  T5 x;
  int refcount;
  T1 y;
  char *c;
};


#include <iostream>

int main()
{
  std::cout 
    <<sizeof C1<C1<X<0>, X<1>, X<2>, X<3>, X<4> >, X<0>, X<1>, X<2>, X<3> >
    <<std::endl;
  return 0;
}


Более частый пример (из std)-

template <class T, class A= std::allocator<T> >
class vector
{
...
A alloc;
...
}


Или такой:

template <class K, class T, class A= std::allocator<pair<K,T> >, class Compare= std::less<K> >
class map
{
...
A alloc;
Compare compare;
...
}
[/ccode]

классы std::less и allocator тоже пусты. Я абсолютно соласен, что они должны занимать место, когда в них что-то есть.

Получается, нарушается основная идеология C++: программист не доплатить за то, что не использует.
Правильно работающая программа — просто частный случай Undefined Behavior
Re: Тратим место впустую, или почему sizeof(T) вседа != 0
От: davenger  
Дата: 16.02.04 11:11
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Для чего проектировщики С++ постановили, что тип не может быть нулего размера?

Если бы размер мог быть равен 0, то невозможно бы ло бы работать с массивами элементов такого типа (адресная арифметика накрылась бы).

_W>Столько места впустую пропадает!

_W>Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.

При наследовании от пустых стратегий место может не теряться если компилер поддерживает оптимизацию пустого базового класса. Об этом можно почитать с книге про шаблоны Вандевурда и Джосаттиса.


_W>Вот, например, этот код у меня выводит значение "56"!!!

_W>А с #pragma pack(1) — "41"!!!

И в релиз версии?
Re: Тратим место впустую, или почему sizeof(T) вседа != 0
От: Анатолий Широков СССР  
Дата: 16.02.04 11:12
Оценка:
[ccode]
struct X {};
struct D : X {int i;};
/ccode]

У меня sizeof(D) == 4 и эта оптимизации разрешена стандартом.
Re: Тратим место впустую, или почему sizeof(T) вседа != 0
От: jazzer Россия Skype: enerjazzer
Дата: 16.02.04 11:17
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Для чего проектировщики С++ постановили, что тип не может быть нулего размера?


Тип не может быть нулевого размера, потому что объект типа должен где-то храниться в памяти ( помните заклинание "object is a region of storage"?), иметь адрес, а на что будет указывать тогда указатель для такого типа? А представь себе массив таких объектов?

_W>Столько места впустую пропадает!

_W>Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.

А вот если данный объект пустого класса является подобъектом своего наследника, то к нему применима описанная в Стандарте "оптимизация пустых базовых классов", т.е. он не будет занимать памяти в составе объекта производного класса.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Тратим место впустую, или почему sizeof(T) вседа != 0
От: Кодт Россия  
Дата: 16.02.04 11:24
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Для чего проектировщики С++ постановили, что тип не может быть нулего размера?

_W>Столько места впустую пропадает!
_W>Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.

Указатель на метод класса с виртуальной базой тоже занимает охренеть сколько. (по-моему, до 5 двордов).

Про оптимизацию пустых баз уже сказали.
А если ты заведомо знаешь, что
template<class Strategy>
class Executor
{
  Strategy strategy; // model of Default Constructible
public:
  method(...)
  { ... strategy.action() ... }
}

то не лучше ли вообще делать
  method(...)
  { ... Strategy().action() ... }

?

Опять же, если методы стратегии инлайновые и стратегия не используется "по ссылке", то её экземпляр вообще не будет создан.
Перекуём баги на фичи!
Re[2]: Тратим место впустую, или почему sizeof(T) вседа != 0
От: _Winnie Россия C++.freerun
Дата: 16.02.04 11:39
Оценка:
>>На что будет указывать тогда указатель для такого типа?
Куда нибуть Хоть на Oxffffffff Компилятор же ведь все равно не будет присваивать туда что-либо для пустого типа.
>>А представь себе массив таких объектов?
Представил. И что в этом такого? Тоже самое, что и пустой объект. sizeof этого массива тоже будет 0. Какие это может создать проблемы? Если конечно, не выяснять размер массива дедовским способом sizeof(array)/sizeof(*array)

>>А вот если данный объект пустого класса является подобъектом своего наследника, то к >>нему применима описанная в Стандарте "оптимизация пустых базовых классов", т.е. он не >>будет занимать памяти в составе объекта производного класса.



Жаль. Я компилировал в IC++ 8.0, Release. Может он хочет какой-нибудь ключик? Который для баго-совместимости с MSVC не включен по умолчанию? Может уже кто-то сталкивался с этой проблемой, а то у него этих ключей вагон и маленький мешок, искать это в документации долго.

А оптимизация пустых членов есть? Ну как тот A alloc. В каком разделе стандарта смотреть?
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: Тратим место впустую, или почему sizeof(T) вседа != 0
От: Павел Кузнецов  
Дата: 16.02.04 11:46
Оценка:
Здравствуйте, _Winnie, Вы писали:

W> Я компилировал в IC++ 8.0, Release.


В случае множественного наследования оптимизация пустых баз обычно не
выполняется.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Тратим место впустую, или почему sizeof(T) вседа != 0
От: WolfHound  
Дата: 16.02.04 11:54
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В случае множественного наследования оптимизация пустых баз обычно не

ПК>выполняется.
Интересно почему?
Я тут поигрался с VC++7.1 дык вот когда 1 или 2 пустые базы то эта оптимизация идет, а начиная с 3ей каждая добавляет по 1 байту к размеру.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Тратим место впустую, или почему sizeof(T) вседа != 0
От: jazzer Россия Skype: enerjazzer
Дата: 16.02.04 12:33
Оценка:
Здравствуйте, _Winnie, Вы писали:

что, определение Стандарта "object is a region of storage" игнорируем?
разные объекты — разные области хранения. Разные области хранения — разные адреса этих областей.

>>>На что будет указывать тогда указатель для такого типа?

_W>Куда нибуть :) Хоть на Oxffffffff Компилятор же ведь все равно не будет присваивать туда что-либо для пустого типа.

куда конкретно? если у тебя есть 2 разных объекта, у них должны быть разные адреса.
Если ты пишешь
MyEmptyClass a,b,c,d;
то очевидно, что a,b,c и в — это разные объекты.

>>>А представь себе массив таких объектов?

_W>Представил. И что в этом такого? Тоже самое, что и пустой объект. sizeof этого массива тоже будет 0. Какие это может создать проблемы? Если конечно, не выяснять размер массива дедовским способом sizeof(array)/sizeof(*array) :)

и все члены массива — это тоже разные объекты.
И никто тебе не помешает ввести для твоего пустого класса тривиальную метрику, определив оператор==, который будет просто сравнивать this.

>>>А вот если данный объект пустого класса является подобъектом своего наследника, то к >>нему применима описанная в Стандарте "оптимизация пустых базовых классов", т.е. он не >>будет занимать памяти в составе объекта производного класса.



_W>Жаль. Я компилировал в IC++ 8.0, Release. Может он хочет какой-нибудь ключик? Который для баго-совместимости с MSVC не включен по умолчанию? Может уже кто-то сталкивался с этой проблемой, а то у него этих ключей вагон и маленький мешок, искать это в документации долго.


Понятия не имею, я на солярке.

_W>А оптимизация пустых членов есть? Ну как тот A alloc. В каком разделе стандарта смотреть?


а чем члены отличаются от простых переменных?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Тратим место впустую, или почему sizeof(T) вседа != 0
От: _Winnie Россия C++.freerun
Дата: 16.02.04 12:47
Оценка:
Здравствуйте, jazzer, Вы писали:


J>И никто тебе не помешает ввести для твоего пустого класса тривиальную метрику, определив оператор==, который будет просто сравнивать this.


Тогда да. А если я его не ввожу? Если я не хочу платить, за то что я не использую?

_W>>А оптимизация пустых членов есть? Ну как тот A alloc. В каком разделе стандарта смотреть?

J>а чем члены отличаются от простых переменных?

Получается, что компилятор зря отводит место под них место

Похоже, мне придется смирится, и ввести себя аккуратней, как советует КотД. Но все равно, часто бывает так, что нужно именно наследование\ или член (на всякий случай, тот же компаратор или аллокатор), и за это "на всякий случай" приходится страдать. В документации IC++ по поводу отимизации пустых базовых классов ни чего не нашел.

Спасибо.
Правильно работающая программа — просто частный случай Undefined Behavior
Re[5]: Тратим место впустую, или почему sizeof(T) вседа != 0
От: jazzer Россия Skype: enerjazzer
Дата: 16.02.04 13:15
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Здравствуйте, jazzer, Вы писали:



J>>И никто тебе не помешает ввести для твоего пустого класса тривиальную метрику, определив оператор==, который будет просто сравнивать this.


_W>Тогда да. А если я его не ввожу? Если я не хочу платить, за то что я не использую?


_W>>>А оптимизация пустых членов есть? Ну как тот A alloc. В каком разделе стандарта смотреть?

J>>а чем члены отличаются от простых переменных?

_W>Получается, что компилятор зря отводит место под них место :(


_W>Похоже, мне придется смирится, и ввести себя аккуратней, как советует КотД. Но все равно, часто бывает так, что нужно именно наследование\ или член (на всякий случай, тот же компаратор или аллокатор), и за это "на всякий случай" приходится страдать. В документации IC++ по поводу отимизации пустых базовых классов ни чего не нашел. :(


_W>Спасибо.


Был тут когда-то топик на тему "А почему компилятор тратит впустую память и не удаляет из объекта неиспользуемые члены класса?"
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.