powered by simpleCommunicator - 2.0.36     © 2025 Programmizd 02
Форумы / C++ [игнор отключен] [закрыт для гостей] / Аллокация в конструктора массива
11 сообщений из 61, страница 3 из 3
Аллокация в конструктора массива
    #40106804
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну я
Место на стеке освободится если бы alloca стоял внутри {}.

Инициализаторы выполняются в стек фрейме конструктора.
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40106808
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl
В стандарте С alloca - есть.
В стандарте С++ std::alloca - нет.

В C тоже нет, и в POSIX тоже ))
Но это не отменяет того факта что на многих платформах эта фича существует.
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40106823
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky
White Owl
В стандарте С alloca - есть.
В стандарте С++ std::alloca - нет.

В C тоже нет, и в POSIX тоже ))
Но это не отменяет того факта что на многих платформах эта фича существует.


man allocaCONFORMING TO
This function is not in POSIX.1.

There is evidence that the alloca() function appeared in 32V, PWB, PWB.2, 3BSD, and 4BSD. There is a man page for it in 4.3BSD.
Linux uses the GNU version.


Так что да, в стандарте нет, но в реальных библиотеках все-же есть.
Во всяком случае во всех никсовых библиотеках есть.
А мелкомягкие дают _alloca и _malloca.
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40106877
Фотография ну я
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_dev
ну я, разве в стандарте C/C++ есть функции alloca/std::alloca ?

Нет, в стандарте языка нет такого.
http://www.c-cpp.ru/content/alloca
Другое дело что это в компиляторах есть и трактуется одинаково.
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40106952
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl, нет в стандарте ANSI C никакой alloca().
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40106973
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl, "легально" такие вещи реализуются на стеке через placement new.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
#include <cstdlib>
#include <cstdio>
#include <cstdint>

using namespace std;

class Pointer
{

  size_t    cnt;
  uint64_t  array[0];

public:

  size_t count() const
  {
    return this->cnt;
  }

  Pointer ( size_t len )
      : cnt( ( len - ( reinterpret_cast<uint8_t*>( this->array )
              - reinterpret_cast<uint8_t*>( this ) )
          ) / sizeof( this->array[0] ) )
  {}
  
  void* operator new ( size_t size, void* p_ )
  {
    return p_;
  }
};

int main( int argc, char** argv )
{
  uint8_t arr[ sizeof( uint64_t ) * 100 + sizeof( Pointer ) ];
  Pointer & ptr = *new ( &arr ) Pointer( sizeof( arr ) );
  std::printf( "\n%zu\n", ptr.count() );
  std::fflush( stdout );
  return 0;
}

...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40109762
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
indigodye0, может быть собеседующий действительно имел в виду alloca + placement new?
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <malloc.h>
#include <new>

class stack_buf_t {
private:
  uint64_t _elems[1]; // должен быть последним полем в классе

public:
  static size_t size(int capacity) {
    assert(capacity >= 0);
    return offsetof(stack_buf_t, _elems) + capacity * sizeof(uint64_t);
  }

  // не используйте напрямую, используйте макрос STACK_BUF
  stack_buf_t(int capacity, uint64_t initial_value) {
    assert(capacity >= 0);
    for (int i = 0; i < capacity; i++) {
      _elems[i] = initial_value;
    }
  }

  uint64_t elem(int index) const {
    return _elems[index];
  }
};

// ! внимание: параметр capacity вычисляется 2 раза
#define STACK_BUF(capacity, initial_value) \
  (new(_alloca(stack_buf_t::size(capacity))) stack_buf_t(capacity, initial_value))

void do_something(int count) {
  stack_buf_t* b = STACK_BUF(count, 3);
  for (int i = 0; i < count; i++) {
    assert(b->elem(i) == 3);
  }
}

Но я бы не стал так делать, потому что alloca -- это хождение по тонкому льду :).
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40109961
priti40
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Пётр Седов

[/src]Но я бы не стал так делать, потому что alloca -- это хождение по тонкому льду :).


Ага то есть Вы ка бы вывернули класс мехом на изнанку и положили все на стек

А что тут опасного ?
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40110012
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Зачем все усложнять? ))
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
#include <memory_resource>
#include <vector>

int main()
{
    // выделяем буфер на стеке для 100 элементов
    char pool[100*sizeof(uint64_t)];
    std::pmr::monotonic_buffer_resource pool_res{pool, sizeof(pool)};

    // используем его в обычном векторе (можно упаковать в класс с нужным апи)
    std::pmr::vector<uint64_t> v1{&pool_res};
    v1.reserve(10);
    v1.push_back(1);
    v1.push_back(2);

    // куча не задействована (пока не вышли за пределы буфера)
}
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40110182
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
priti40
А что тут опасного ?
У меня когда-то давно был примерно такой код:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
void some_func() {
  for (int i = 0; i < примерно_тысяча; i++) {
    another_func();
  }
}

void another_func() {
  указатель = _alloca(примерно_тысяча);
  ...
}

Компилятор Visual C++ 6, в Debug конфигурации всё было нормально. Но вот в Release конфигурации компилятор зачем-то inline-ил вызов функции another_func (хотя она была не такая уж и маленькая), и работало оно так, как будто код такой:
Код: plaintext
1.
2.
3.
4.
5.
6.
void some_func() {
  for (int i = 0; i < примерно_тысяча; i++) {
    указатель = _alloca(примерно_тысяча);
    ...
  }
}

В Win32 для stack-а главного thread-а по умолчанию резервируется диапазон в 1 мб виртуальных адресов. Вот весь этот мегабайт исчерпывался, и программа crash-илась со stack overflow. С тех пор я понял, что alloca -- это грабли, и перестал его использовать. Хотя современный Visual C++ может уже понимает, что не надо inline-ить вызов функции с alloca.

В ATL есть старые макросы для преобразования строк, которые выделяют память через alloca. Потом вместо них сделали более надёжный механизм:
http://msdn.microsoft.com/EN-US/library/87zae4a3(v=VS.120,d=hv.2).aspx ATL and MFC String Conversion Macros
...
There are several important differences between the older string conversion macros and the new string conversion classes:
Old ATL 3.0 Conversion Macros New ATL 7.0 Conversion Classes Allocates memory on the stack.Uses stack memory for small strings. Uses the heap if the stack is not large enough.The string is freed when the function is exited.The string is freed when the variable goes out of scope.Cannot be used in exception handlers.Can be used in exception handlers.Not suitable for use in loops. Memory use grows until the function is exited.Supports use in loops. Loop scope ensures that memory is freed on each iteration.Not good for large strings. Stack space is limited.No problems with large strings. Strings will be allocated on the heap.Usually require USES_CONVERSION to be defined.Never require USES_CONVERSION to be defined.Meaning of OLE depends on definition of OLE2ANSI.OLE is always equivalent to W....
ATL 3.0 String Conversion Macros
...
The destination string is created using _alloca , except when the destination type is BSTR .
Пункт про обработчики исключений сильно настораживает.

Anatoly Moskovsky
Код: plaintext
1.
2.
    // выделяем буфер на стеке для 100 элементов
    char pool[100*sizeof(uint64_t)];

А тут не будет проблем с выравниванием (alignment)? Вроде как для динамических массивов char-ов (new char[size]) гарантируется наилучшее выравнивание, но тут-то массив не динамический. Может лучше так?
Код: plaintext
1.
uint64_t pool[100];
...
Рейтинг: 0 / 0
Аллокация в конструктора массива
    #40110264
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пётр Седов
А тут не будет проблем с выравниванием (alignment)?

Нет. Гарантируется правильное выравнивание. Как и для любых других аллокаторов.
https://en.cppreference.com/w/cpp/memory/memory_resource/allocate

Хотя конечно если буфер сразу выровнен, то не будет потерян первый невыровненный кусок. Но это всего лишь оптимизация, а не необходимость.
...
Рейтинг: 0 / 0
11 сообщений из 61, страница 3 из 3
Форумы / C++ [игнор отключен] [закрыт для гостей] / Аллокация в конструктора массива
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]