Любая альтернатива std:: dynarray в настоящее время доступна?

С++ 11 дал нам отличный std::array, который требует, чтобы размер был известен во время компиляции:

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

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

С++ 14 будет определять std::dynarray для покрытия этого случая, но dynarray пока недоступен в GCC 4.7 или в Clang 3.2.

Итак, кто-нибудь знает контейнер, который сопоставим с std::array (с точки зрения эффективности), но не требует указания размера во время компиляции? Я подозреваю, что у Boost есть что-то готовое для меня, хотя я ничего не мог найти.

Ответы

Ответ 1

Вы можете (ab) использовать std::valarray<short>.

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<short> dyn_array (raw_array, length);
    for (short elem : dyn_array) {
        std::cout << elem << std::endl;
    }

    // ...

    free(raw_array);
}

valarray поддерживает большинство функций dynarray, за исключением:

  • Распределитель
  • обратный итератор
  • .at()
  • .data()

Обратите внимание, что стандарт (по состоянию на n3690) не требует непрерывного хранения valarray, хотя нет причин не делать этого:).

(Для некоторой детали реализации в libstdС++ она реализована как пара (длина, данные), а в libС++ реализована как (начало, конец).)

Ответ 2

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

Ответ 3

Положите голосование на std::unique_ptr<short[]>(new short[n]), если вам не нужен доступ к диапазону доступа, предоставляемый std::dynarray<T>::at(). Вы даже можете использовать список инициализаторов:

#include <iostream>
#include <memory>

int main(int argc, char** argv) {
  const size_t n = 3;
  std::unique_ptr<short[]> myarray(new short[n]{ 1, 2, 3 });
  for (size_t i = 0; i < n; ++i)
    std::cout << myarray[i] << '\n';
}

Ответ 4

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

Множество шаблонов, но что-то вроде этого:

template<typename T>
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<iterator>       reverse_iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  typedef size_t                                size_type;
  typedef ptrdiff_t                             difference_type;

  std::size_t length;
  std::unique_ptr<T[]> 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<T[]> tmp( new T[o.length] );
    std::copy( o.begin(), o.end(), tmp.get() );
    length = o.length;
    buffer = std::move(tmp);
    return *this;
  }
};

at() отсутствует, как и распределители.

operator= отличается от предложения dyn_array - блоков предложений operator=, я даю ему семантику значений. Несколько методов менее эффективны (например, конструкция copy). Я разрешаю пустое fixed_buffer.

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

Ответ 5

С++ 14 также добавляет массивы переменной длины, аналогичные тем, что на C99, и которые уже поддерживаются некоторыми компиляторами:

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

Это не контейнер, поскольку он не поддерживает begin() и end() и т.д., но может быть работоспособным решением.

Ответ 6

dynarray очень легко реализовать себя без компонента распределения стека, что, по-видимому, невозможно сделать до тех пор, пока, возможно, С++ 14 в любом случае, поэтому я просто перевернул обратный-обратный dynarray (forwardport?) как часть моей библиотеки и начал использовать ее с тех пор. Работает на С++ 03 без каких-либо положений "пустоты в Небраске", так как это не совсем зависит от каких-либо специфических возможностей С++ 11, и он опрятен иметь
Таким образом, когда С++ 1y/2z dynarray приходит, мой код по-прежнему по большей части совместим.

(Это также одно из многих очевидных "почему у С++ не было этого раньше?", так что хорошо иметь его вокруг).

Это было до того, как я узнал, что, по-видимому, С++ 1y- dynarray и С++ 1y-runtime-size-массивы - это одно и то же предложение (одно просто синтаксическое сахара для другого), а не два разных, но -комплементарные предложения, как я впервые подумал. Поэтому, если бы мне пришлось решить тот же вопрос в настоящее время, я бы, вероятно, переключился на что-то, основанное на правильном решении @Yakk.