C ++ 11 дал нам здорово std::array
, который требует, чтобы размер был известен во время компиляции:
std::array<int, 3> myarray = {1, 2, 3};
Теперь у меня есть некоторые старые short*
буферы для переноса, размер которых будет известен (и, конечно, будет) только во время выполнения.
C ++ 14 определит std::dynarray
чтобы покрыть это дело, но dynarray
пока недоступен ни в GCC 4.7, ни в Clang 3.2.
Итак, кто-нибудь знает контейнер, который сопоставим с std::array
(с точки зрения эффективности), но не требует указывать размер во время компиляции? Я подозреваю, что у Буста кое-что готово для меня, хотя я не мог ничего найти.
Вы могли бы (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
хранение должно быть непрерывным, хотя нет причин не делать этого :).
(Для некоторых деталей реализации в libstdc ++ он реализован как пара (длина, данные), а в libc ++ он реализован как (начало, конец).)
Я думаю std::vector
это то, что вы ищете раньше dynarray
становится доступным. Просто используйте конструктор выделения или reserve
и вы избежите перераспределения накладных расходов.
Я проголосую за 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';
}
Буфер и размер, а также некоторые основные методы дают вам большую часть того, что вы хотите.
Много шаблонного, но как то так:
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.
C ++ 14 также добавляет массивы переменной длины, аналогичные массивам в C99, и это уже поддерживается некоторыми компиляторами:
void foo(int n) {
int data[n];
// ...
}
Это не контейнер, так как он не поддерживает begin()
а также end()
и т. д., но может быть осуществимым решением.
dynarray
очень легко реализовать себя без компонента выделения стека, что, по-видимому, невозможно сделать до возможно C ++ 14 в любом случае — так что я просто бросил dynarray
inverse-backport (forwardport?) как часть моей библиотеки и начал использовать его с тех пор. Работает в C ++ 03 без каких-либо предложений «void in Nebraska», так как это абсолютно не зависит от какой-либо специфической для C ++ 11 возможности, и это очень удобно иметь
Таким образом, когда C ++ 1y / 2z dynarray
приходит мой код по-прежнему по большей части совместим.
(Это также одна из многих очевидных вещей «почему в С ++ такого не было раньше?», Так что хорошо бы иметь это рядом).
Это было до того, как я узнал, что, по-видимому, C ++ 1y-dynarray
и C ++ 1y-runtime-size-массивы — это то же самое предложение (одно — просто синтаксический сахар для другого), а не два разных, но дополняющих предложения, как я сначала подумал. Так что если бы мне пришлось сейчас решать тот же вопрос, я бы наверное переключитесь на что-то основанное на решении @ Yakk для корректности.