Для чего проектировщики С++ постановили, что тип не может быть нулего размера?
Столько места впустую пропадает!
Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.
Вот, например, этот код у меня выводит значение "56"!!!
А с #pragma pack(1) — "41"!!!
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
Здравствуйте, _Winnie, Вы писали:
_W>Для чего проектировщики С++ постановили, что тип не может быть нулего размера?
Если бы размер мог быть равен 0, то невозможно бы ло бы работать с массивами элементов такого типа (адресная арифметика накрылась бы).
_W>Столько места впустую пропадает! _W>Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.
При наследовании от пустых стратегий место может не теряться если компилер поддерживает оптимизацию пустого базового класса. Об этом можно почитать с книге про шаблоны Вандевурда и Джосаттиса.
_W>Вот, например, этот код у меня выводит значение "56"!!! _W>А с #pragma pack(1) — "41"!!!
И в релиз версии?
Re: Тратим место впустую, или почему sizeof(T) вседа != 0
Здравствуйте, _Winnie, Вы писали:
_W>Для чего проектировщики С++ постановили, что тип не может быть нулего размера?
Тип не может быть нулевого размера, потому что объект типа должен где-то храниться в памяти ( помните заклинание "object is a region of storage"?), иметь адрес, а на что будет указывать тогда указатель для такого типа? А представь себе массив таких объектов?
_W>Столько места впустую пропадает! _W>Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.
А вот если данный объект пустого класса является подобъектом своего наследника, то к нему применима описанная в Стандарте "оптимизация пустых базовых классов", т.е. он не будет занимать памяти в составе объекта производного класса.
Здравствуйте, _Winnie, Вы писали:
_W>Для чего проектировщики С++ постановили, что тип не может быть нулего размера? _W>Столько места впустую пропадает! _W>Часто шаблон наследуется от (пустых!) стратегий. И в результате какой-нибуть умный указатель, вместо того, что бы занимать 4 или 8 байт, занимает охренеть сколько.
Указатель на метод класса с виртуальной базой тоже занимает охренеть сколько. (по-моему, до 5 двордов).
Про оптимизацию пустых баз уже сказали.
А если ты заведомо знаешь, что
template<class Strategy>
class Executor
{
Strategy strategy; // model of Default Constructiblepublic:
method(...)
{ ... strategy.action() ... }
}
то не лучше ли вообще делать
method(...)
{ ... Strategy().action() ... }
?
Опять же, если методы стратегии инлайновые и стратегия не используется "по ссылке", то её экземпляр вообще не будет создан.
Перекуём баги на фичи!
Re[2]: Тратим место впустую, или почему sizeof(T) вседа != 0
>>На что будет указывать тогда указатель для такого типа?
Куда нибуть Хоть на Oxffffffff Компилятор же ведь все равно не будет присваивать туда что-либо для пустого типа. >>А представь себе массив таких объектов?
Представил. И что в этом такого? Тоже самое, что и пустой объект. sizeof этого массива тоже будет 0. Какие это может создать проблемы? Если конечно, не выяснять размер массива дедовским способом sizeof(array)/sizeof(*array)
>>А вот если данный объект пустого класса является подобъектом своего наследника, то к >>нему применима описанная в Стандарте "оптимизация пустых базовых классов", т.е. он не >>будет занимать памяти в составе объекта производного класса.
Жаль. Я компилировал в IC++ 8.0, Release. Может он хочет какой-нибудь ключик? Который для баго-совместимости с MSVC не включен по умолчанию? Может уже кто-то сталкивался с этой проблемой, а то у него этих ключей вагон и маленький мешок, искать это в документации долго.
А оптимизация пустых членов есть? Ну как тот A alloc. В каком разделе стандарта смотреть?
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: Тратим место впустую, или почему sizeof(T) вседа != 0
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>В случае множественного наследования оптимизация пустых баз обычно не ПК>выполняется.
Интересно почему?
Я тут поигрался с VC++7.1 дык вот когда 1 или 2 пустые базы то эта оптимизация идет, а начиная с 3ей каждая добавляет по 1 байту к размеру.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Тратим место впустую, или почему sizeof(T) вседа != 0
что, определение Стандарта "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. В каком разделе стандарта смотреть?
J>И никто тебе не помешает ввести для твоего пустого класса тривиальную метрику, определив оператор==, который будет просто сравнивать this.
Тогда да. А если я его не ввожу? Если я не хочу платить, за то что я не использую?
_W>>А оптимизация пустых членов есть? Ну как тот A alloc. В каком разделе стандарта смотреть? J>а чем члены отличаются от простых переменных?
Получается, что компилятор зря отводит место под них место
Похоже, мне придется смирится, и ввести себя аккуратней, как советует КотД. Но все равно, часто бывает так, что нужно именно наследование\ или член (на всякий случай, тот же компаратор или аллокатор), и за это "на всякий случай" приходится страдать. В документации IC++ по поводу отимизации пустых базовых классов ни чего не нашел.
Спасибо.
Правильно работающая программа — просто частный случай Undefined Behavior
Re[5]: Тратим место впустую, или почему sizeof(T) вседа != 0
Здравствуйте, _Winnie, Вы писали:
_W>Здравствуйте, jazzer, Вы писали:
J>>И никто тебе не помешает ввести для твоего пустого класса тривиальную метрику, определив оператор==, который будет просто сравнивать this.
_W>Тогда да. А если я его не ввожу? Если я не хочу платить, за то что я не использую?
_W>>>А оптимизация пустых членов есть? Ну как тот A alloc. В каком разделе стандарта смотреть? J>>а чем члены отличаются от простых переменных?
_W>Получается, что компилятор зря отводит место под них место :(
_W>Похоже, мне придется смирится, и ввести себя аккуратней, как советует КотД. Но все равно, часто бывает так, что нужно именно наследование\ или член (на всякий случай, тот же компаратор или аллокатор), и за это "на всякий случай" приходится страдать. В документации IC++ по поводу отимизации пустых базовых классов ни чего не нашел. :(
_W>Спасибо.
Был тут когда-то топик на тему "А почему компилятор тратит впустую память и не удаляет из объекта неиспользуемые члены класса?"