Будь-яка альтернатива std :: dynarray наразі доступна?

C ++ 11 дав нам чудовий std :: array , який вимагає розміру бути відомим під час компіляції:

std::array myarray = {1, 2, 3};

Тепер я маю кілька старих буферів short * для обертання, розмір яких буде відомий (і це, звичайно ж, буде) тільки під час виконання.

C ++ 14 буде визначати std :: dynarray для покриття цього випадку, але dynarray ще не доступний в GCC 4.7 або в Clang 3.2.

Отже, чи знає кожен контейнер, який можна порівняти з std :: array (з точки зору ефективності), але не вимагає вказати розмір у час компіляції? Я підозрюю, що Boost має щось готовий для мене, хоча я нічого не міг знайти.

15
Проблема з повідомленням "C + + 14 буде", перш ніж C ++ 14 існує, це те, що добре, C ++ 14 ще не існує: -S
додано Автор Kerrek SB, джерело
@chris дякую за підказку.
додано Автор Stefano Sanfilippo, джерело
Динамічні можливості важкоатлетів і тут не потрібні. Мені потрібен контейнер із фіксованим розміром, що нагадує старий масив C, але з деякими доданими метаданими та можливістю ітерації.
додано Автор Stefano Sanfilippo, джерело
@StefanoSanfilippo, проблем немає. Я дізнався так само з мого запитання, крім редагування, що мав лише посилання в резюме.
додано Автор chris, джерело
Я вилучив ваш тег C ++ 14. Це мета запитання прийшов до консенсусу, щоб зачекати до остаточного випуску стандартного проекту, перш ніж використовувати його з C ++ 1 рік.
додано Автор chris, джерело
Зверніть увагу, що високий шанс dynarray не буде перетворено в C ++ 14, оскільки, як видається, не існує досвіду впровадження щодо частини виділення стека, і є й інші проблеми. .
додано Автор Xeo, джерело
Ви все ще можете використовувати std :: vector і reserve() розмір, який потрібно заздалегідь. Таким чином, ви не вдарите розмір пені під час вставки.
додано Автор Anthony Vallée-Dubois, джерело
Чому не std :: вектор?
додано Автор Anthony Vallée-Dubois, джерело

6 Відповіді

Я думаю, що std :: vector це те, що ви шукаєте, перш ніж dynarray стане доступним. Просто скористайтеся конструктором, що розподіляє, або reserve , щоб уникнути перерозподілу накладних витрат.

17
додано
@ user814628 і це припущення дозволяє оптимізувати контейнер.
додано Автор Stefano Sanfilippo, джерело
Чому така спеціалізація? Більш ефективний код push_back я припускаю?
додано Автор dchhetri, джерело
Яка основна відмінність між dynarray та vector?
додано Автор dchhetri, джерело
@ DavidRodríguez-dribeas З огляду на \ constant number n , як ми можемо виділити n-elements на стек у runtime?
додано Автор dchhetri, джерело
Я думаю, що C ++ прагне бути максимально ефективним, але, схоже, спеціалізується на кожній дрібниці, яка дозволить оптимізувати. Більше варіант не може зашкодити, але може бути переважним з усіма цими виборами
додано Автор dchhetri, джерело
@ user814628 vector можна змінити після створення, to-be- dynarray не може.
додано Автор Angew, джерело
@ user814628: Припущення, що реалізація бібліотеки зможе виділити елементи у стекі у випадку std :: dynarray , що зробить його ближче до VLA в C. Якщо це є Тоді dynarray не покриває витрати на розподіл, але це не є тривіальним для реалізації dynarray (принаймні як бібліотека)
додано Автор David Rodríguez - dribeas, джерело
@ user814628, використовуючи стек-розподілені динамічні масиви, які також входять до C ++ 14.
додано Автор Miles Rout, джерело
@ user814628 з alloca
додано Автор Jean-Michaël Celerier, джерело

I’ll put in a vote for std::unique_ptr(new short[n]) if you don’t need the range-checked access provided by std::dynarray::at(). You can even use an initializer list:

#include 
#include 

int main(int argc, char** argv) {
  const size_t n = 3;
  std::unique_ptr myarray(new short[n]{ 1, 2, 3 });
  for (size_t i = 0; i < n; ++i)
    std::cout << myarray[i] << '\n';
}
10
додано
@andre Це не те ж саме. нюхати . Крім того, вам слід пам'ятати, що 3 десь, який dynarray запам'ятовує вас.
додано Автор Yakk - Adam Nevraumont, джерело
Але ... але ви не можете використовувати сильний код циклу for для циклу!
додано Автор Yakk - Adam Nevraumont, джерело
пара > ? ;)
додано Автор Jon Purdy, джерело
@Yakk True true ...;), але ви можете використовувати std :: for_each (myarray.get (), myarray.get() + 3, [] (короткий val) {std :: cout << val << "\ n ";});
додано Автор André, джерело
Ви повинні написати функцію make_unique і використовувати її, а не писати new .
додано Автор Miles Rout, джерело

You could (ab)use a std::valarray.

int main() {
    short* raw_array = (short*) malloc(12 * sizeof(short));
    size_t length = 12;
    for (size_t i = 0; i < length; ++ i) {
        raw_array[i] = (short) i;
    }

   //...

    std::valarray dyn_array (raw_array, length);
    for (short elem : dyn_array) {
        std::cout << elem << std::endl;
    }

   //...

    free(raw_array);
}

valarray supports most features of a dynarray, except:

  • розподільник
  • зворотний ітератор
  • .at()
  • .data()

Зверніть увагу, що стандарт (за номером n3690) не вимагає постійного зберігання пам'яті valarray , хоча це не означає, що це не слід робити :).

(Для деяких деталей реалізації в libstdc ++ він реалізується як пара (довжина, дані), і в libc ++ він реалізується як (початок, кінець).)

4
додано
Для виділеного використання стека raw_array може бути VLA, якщо він може прийняти використання нестандартних функцій компілятора. Ваш код може бути використаний для впровадження dynarray , доки він не стане доступним.
додано Автор dronus, джерело
Також, на x86_64, копіювання 16 байтів може бути здійснено в одному циклі при правильному вирівнянні, що підвищує ефективність для std :: swap.
додано Автор user877329, джерело
@MatteoItalia Додавання додаткового учасника робить об'єкт у 1,5 рази більше. Крім того, std :: vector може перевизначати пам'ять для підвищення продуктивності.
додано Автор user877329, джерело
Чудово! std :: valarray максимально наближений до чистого масиву (не рахуючи std :: dynarray ), і я в порядку з перерахованими обмеженнями (приємно!).
додано Автор Stefano Sanfilippo, джерело
Що стосується std :: vector , створених з правильним перевантаженням, і просто отримуючи доступ до елементів з оператором [] , ви просто вирізуєте один член даних (ємність). Цей запах багато , як мені передчасна оптимізація ...
додано Автор Matteo Italia, джерело
Чому malloc() ? Чому б не raw_array = new short (12); ?
додано Автор user529758, джерело
Я б сказав, що справа для dynarray - це більше про оборонне програмування, ніж про оптимізацію - це не повинно можна змінити розмір масиву, який не змінює розмір бізнесу.
додано Автор Chris Hiszpanski, джерело

Буфер і розмір, а також деякі основні методи дають вам більшу частину того, що ви хочете.

Багато боліплата, але щось на зразок цього:

template
struct fixed_buffer {
  typedef       T                               value_type;
  typedef       T&                              reference;
  typedef const T&                              const_reference;
  typedef       T*                              iterator;
  typedef const T*                              const_iterator;
  typedef std::reverse_iterator       reverse_iterator;
  typedef std::reverse_iterator const_reverse_iterator;
  typedef size_t                                size_type;
  typedef ptrdiff_t                             difference_type;

  std::size_t length;
  std::unique_ptr buffer;

  std::size_t size() const { return length; }

  iterator begin() { return data(); }
  const_iterator begin() const { return data(); }
  const_iterator cbegin() const { return data(); }
  iterator end() { return data()+size(); }
  const_iterator end() const { return data()+size(); }
  const_iterator cend() const { return data()+size(); }

  reverse_iterator rbegin() { return {end()}; }
  const_reverse_iterator rbegin() const { return {end()}; }
  const_reverse_iterator crbegin() const { return {end()}; }
  reverse_iterator rend() { return {begin()}; }
  const_reverse_iterator rend() const { return {begin()}; }
  const_reverse_iterator crend() const { return {begin()}; }

  T& front() { return *begin(); }
  T const& front() const { return *begin(); }
  T& back() { return *(begin()+size()-1); }
  T const& back() const { return *(begin()+size()-1); }
  T* data() { return buffer.get(); }
  T const* data() const { return buffer.get(); }
  T& operator[]( std::size_t i ) { return data()[i]; }
  T const& operator[]( std::size_t i ) const { return data()[i]; }
  fixed_buffer& operator=(fixed_buffer &&) = default;
  fixed_buffer(fixed_buffer &&) = default;

  explicit fixed_buffer(std::size_t N):length(N), buffer( new T[length] ) {}
  fixed_buffer():length(0), buffer() {}

  fixed_buffer(fixed_buffer const& o):length(o.N), buffer( new T[length] )
  {
    std::copy( o.begin(), o.end(), begin() );
  }
  fixed_buffer& operator=(fixed_buffer const& o)
  {
    std::unique_ptr tmp( new T[o.length] );
    std::copy( o.begin(), o.end(), tmp.get() );
    length = o.length;
    buffer = std::move(tmp);
    return *this;
  }
};

at() is missing, as are allocators.

operator= is different than dyn_array proposal -- the proposal blocks operator=, I give it value semantics. A few methods are less efficient (like copy construction). I allow empty fixed_buffer.

Це, ймовірно, заблокує можливість використання стеків для зберігання dyn_array , що, ймовірно, чому це не дозволяє. Просто видаліть мій operator = і тривіальний конструктор, якщо ви хочете ближче до dyn_array поведінки.

4
додано
@FelixPetriconi alloca (виділення на основі стеку) було б важко підтримати, оскільки пам'ять не може бути повернута з функції через функцію alloca ! Вам доведеться приймати "обчислювальний" лямбда, яка буде "тілом", в межах якого масив був дійсним, або містять пропуск із вмістом в alloca "для пам'яті.
додано Автор Yakk - Adam Nevraumont, джерело
Наскільки я знаю, std :: dynarray виділяє пам'ять на стек, тому можна було б розширити або змінити вищезгаданий шаблон таким чином, щоб він не виділяв пам'ять на купі, але використовує зовнішню пам'ять, яка була розподілена з alloc (sizeof ( T) * NUMBER_OF_ELEMENTS) Потрібно лише зателефонувати на місце конструктора на всі елементи всередині шаблону "c'tor" і називати д'ор на знищення. Я не перевірив це, але це не повинно бути надто складним для реалізації
додано Автор Felix Petriconi, джерело

C ++ 14 також додає масивів змінної довжини, подібні до тих, що містяться в C99, і це вже підтримується деякими компіляторами:

void foo(int n) {
  int data[n];
 //...
}

Це не контейнер, оскільки він не підтримує begin() і end() тощо, але це може бути дієвим рішенням.

0
додано
Вони не називаються масивів змінної довжини, і не дуже схожі на CLA VLA, крім синтаксису декларації.
додано Автор Ben Voigt, джерело
"Масиви runtime bound", але вони отримали від C ++ 14
додано Автор Jonathan Wakely, джерело
@BenVoigt: Що вони називають?
додано Автор Janus Troelsen, джерело

dynarray is very easy to implement oneself without the stack-allocation component -which apparently isn't possible to do until perhaps C++14 anyway- so I just rolled a dynarray inverse-backport (forwardport?) as part of my library and started using it ever since. Works in C++03 without any "void in Nebraska" clauses so far, as it doesn't absolutely depend on any C++11-specific capability, and it's neat to have
That way when C++1y/2z dynarray comes along my code is still for the most part compatible.

(Це також одна з багатьох очевидних "чому не C ++ це було раніше", так що це добре, щоб це навколо).

Це було до того, як я дізнався, що, очевидно, C ++ 1y- dynarray і C ++ 1y-runtime-size-масиви - точно така ж пропозиція (це просто синтаксичний цукор для іншого), а не дві різні - але-додаткові пропозиції, як я спочатку подумав. Отже, якщо б мені довелося вирішити одне й те саме питання, то сьогодні я ймовірно перейду на щось на основі рішення @ Yakk для правильності.

0
додано
Чи передбачається це відповідь на питання чи що?
додано Автор Stefano Sanfilippo, джерело
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147