- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
#include <iostream>
#include <alloca.h>
#include <stdlib.h>
#include <new>
using namespace std;
int main(void) {
const size_t N = 5+rand()%4;
char* arr = ::new (alloca(N)) char[N]{1,2,3,4};
for(size_t i=0; i<N; ++i)
cout<<(int)arr[i]<<endl;
cout<<"ok";
return 0;
}
А как std::dynarray работает?
After reviewing national body comments to n3690, this library component was voted out from C++14 working paper into a separate Technical Specification. This container is not a part of the draft C++14 as of n3797
P.S. И где там написано, что он обязан выделять буфер на стеке?
> This way, additional optimization opportunities are possible, for example, using stack-based allocation
Но гарантий никаких :)
Я прикупил кроличью лапку.
Максимум что получится - std::dyn_array<int> a(alloca(sizeof(int)*N));
Тут нужно больше магии...
Ты упоролся? Покажи мне строчку, в которой alloca() добавили в стандарт крестов.
> Аллокатор пишешь, что в allocate вызывает alloca
Лол. Ну напиши, потестируй.
В новом стандарте разве есть alloca? Там, судя по всему, даже std::dynarray по пизде пошел. Покажи мне строчку драфта, в которой описана alloca и ее новое поведение.
std::dynarray нельзя реализовать через alloca т.к. выделенная в его конструкторе память сразу же грохнется на выходе из него. А если конструктор все-таки удастся заинлайнить (что, емнип, компиляторы никогда не делают с функциями, в которых есть alloca) - то цикл с std::dynarray будет пожирать стек, т.к. alloca не понимает скопов.
Поэтому для реализации std::dynarray нужна совсем другая магия, и без допилки компилятора ты его не сделаешь.
Удачи в использовании этой хуйни в цикле, скопам то ты аллоку все равно не научишь ;)
Впрочем, кидай код, мой пукан уже в ожидании... ко-ко-ко
http://ideone.com/eSJ1F5
читер ;)
А ты хотел что ли чтобы я ушел с порванным анусом после такого? ;)
Это есть почти во всех компиляторах. Только написать дифайн на разных компилях подставляемый по разному. С введением атрибутов в С++11 впредь появятся стандартные атрибуты для этого.
Процитирую себя: А если конструктор все-таки удастся заинлайнить (что, емнип, компиляторы никогда не делают с функциями, в которых есть alloca) - то цикл с std::dynarray будет пожирать стек, т.к. alloca не понимает скопов
Короче юзать то можно, как и саму alloca, если понимаешь последствия. Но в стандарте такой хуйне не место, там и без этого UB'ов хватает. Потом будет куча разорванных попок, кричащих "а почему у меня std::dynarray в цикле сегфолтится?".
А еще такую реализацию нельзя юзать на куче или в статике:
http://ideone.com/cEw6Hg
> Модификация компилятора ему видите ли нужна.
Для нормальной реализации - нужна.
В крайнем случае можно создать фрейм стека.
http://ideone.com/j13ahX
Цикл маловат ;) В каком-нибудь while (true) или просто достаточно большом цикле оно покажет себя с лучшей стороны.
> Да ты же гений. Выделил на стеке когда стека не было!
Ну так std::dynarray по стандарту должен был быть безопасным, и выделять память не на стеке, если объект размещается не на стеке (+ еще одно магическое свойство этого класса, которое потребует поддержки от компилера или рантайма). Где там написано, что я не могу его засунуть в другой класс, или создать в куче, или поюзать в большом цикле?
P.S. Короче теперь я понял, почему этот класс не включили в с++14 и послали нахуй в std::experimental.
http://ideone.com/mkXjpG
Никаких переполнений стека.
Да я не о том, что это обойти нельзя. Можно конечно.
Я все-таки о том, что абстракция у этого класса течет сплошным потоком... В крестах и так UB'ов полно, а ты еще такое чудо хочешь туда добавить.
А слабо переделать класс так, чтобы я не мог разместить его инстансы в куче или статике? :)
Вот от такого не спасет :) Абстракция дырявая даже если убить new :(
Это да... :(
Ну это особый контейнер и требует особого отношения, очевидно. Так что
И пугаться нет причины,
Если вы еще мужчины
и знаете кресты
А что если юзать простой и безопасный вариант? Если размер меньше 10 интов - буфер будет размещен в самом объекте. Если больше - в куче. Всегда жрет 10*sizeof(int) байт, но и пофиг, зато потребление стека всегда детерминировано, адекватно работает со скопами, не требует никаких нестандартных функций и атрибутов, нет ограничений по размещению...
аборт
стандарт - для анскильных крестопитухов.
На gcc работает - все нормально
Я писал. Не работает. Хотел заменить std::allocator. Внутри функции allocate выделяет память, а когда выходит из функции удаляет память. Функция возвращает мусор.
Это что там можно словить? Всегда пользовался для оптимизации. Код вылетает редко.
Можно порвать стек, если массив окажется слишком толстым.
Есть не во всех компиляторах (хотя мне такие не попадались).
Возможны баги с циклами (т.к. она не понимает скопов).
Стек! Порвали стек!
Кукарек, кукарек, кукарек...
http://stackoverflow.com/a/3410689/3083709
Тред подтолкнул меня нагуглить boost::pool_allocator, который решает обходным путем задачу без дефекации в стек, который не резиновый.
Все-таки пул, имхо, идеален для одиночных небольших объектов, а не для массивов.
Таким же образом у стека массив тоже забирает непрерывный кусок памяти. К тому же, напомнило: http://govnokod.ru/11495#comment148787
> И будет та же самая фигня, что и с кучей.
Фрагментация, если я правильно понял? Таки да, есть такие проблемы. Если бы std::array или boost::array предоставляли возможность подменить аллокатор, то проблема бы сводилась к написанию аллокатора с аналогичной стеку стратегией выделения памяти из пула. ИМХО это все равно лучше, чем вся эта питушня с alloca. Если б я увидел на работе какой-нибудь "my_super_alloca_array_do_not_touch_magi c" - обиделся бы на всю жизнь, т.к. мне предоставлялась честь прибирать за одним таким изобретателем.
Да там не только она...
- Надо думать о потокобезопасности пула и терять время на блокировки, если мы не делаем thread-local pool'ы (а если делаем - теряем память).
- У пула повышается сложность освобождения от O(1) до O(n) из-за того, что ему надо сортировать пустые блоки во free list'е (иначе он он пропустит половину подходящих мест под массив).
Короче пул превращается в самую обычную кучу. Разве что изолированную.
> проблема бы сводилась к написанию аллокатора с аналогичной стеку стратегией выделения памяти из пула
Дополнительный thread-local стек? А что, это идея! Только его аллокатором оформлять не стоит, т.к. его будут абузить для других структур и расстраиваться - realloc же возможен только у самого свежего, и удаляться все должно строго в обратном порядке... Имхо лучше отдельный спецкласс под такое.
Пока вижу одну проблему - та же фигня, что и с кодом лиспговна - если такой массив запилить в куче, он испортит всю синхронизацию стеков.
Хех, о таких вещах я даже не задумывался: код в топике - о "возне" в стеке, а я не представляю себе ситуацию, при которой один поток начинает модифицировать стек другого.
> повышается сложность освобождения от O(1) до O(n)
Пару лет назад я встречал STL-совместимые set и map для диапазонов значений. Я не математик, но мне кажется, что O(n) можно улучшить до O(log n). Ну, это так, догадки. Похоже, я слишком серьезно отнесся к коду, который написан just for lulz :)
Не-не-не. Сам пул же не в стеке создается, он общий... Вот потоки и подерутся за него.
> можно улучшить до O(log n)
Вполне возможно. Я про конкретную реализацию free list'ов в бустовском пуле. Там прям так и написано - хочешь непрерывные чанки аля массивы - включай сортировку при освобождении и имей O(n).
Про идею хомячка обсуждали чуть выше, где я предложил не оформлять его аллокатором, т.к. далеко не все контейнеры адекватно смогут с таким аллокатором работать. А тут я пишу про конкретный бустовский пул...
я для такой хуйни стек тупо эмулирую
выделение-освобождение за O(1), ассерты проверяют, чтобы освобождалось строго в обратном порядке
я ради такого даже в своём контейнере в деструкторе порядок уничтожения перевернул
Если я правильно понимаю ++ (а я не понимаю) то порядок значения не имеет?
Объекты всегда разрушаются в порядке, обратном созданию. И это правильно. Пример:
A a;
B b(a);
b использует a. Если разрушить a до разрушения b, это может помешать нормальному разрушению b, т.к. b может захотеть что-то сделать с a в деструкторе. Аналогично с наследованием: если B наследует A, это реализуется в виде подобъекта a внутри b. Нельзя разрушать внутренности объекта, пока сам объект не разрушен.
Если массив линкованный - тогда ясен пень с конца.
Какой-какой массив?