Boostのarray.hppをまねて、スタックからメモリを調達する配列を作ってみる。その名もalloca_array。
機能:
・スタック上に、動的にサイズが決定される配列を作る
(いったん作られた後は大きさを変更できない)。
・STLコンテナである。begin()やらend()やらが提供される。
--------------- alloca_array.hppここから ---------------
#if ! defined ALLOCA_ARRAY_H
#include <cassert>
#include <cstddef>
#if defined _MSC_VER
#include <malloc.h>
#define alloca _alloca
#elif defined _GCC
#include <alloca.h>
#else
#error "unsupported compiler"
#endif
#define DECL_ALLOCA_ARRAY(variable, ElemType, count) alloca_array<ElemType> variable(alloca(count * sizeof(ElemType)), (count))
template<typename ElemType>
class alloca_array {
public:
typedef ElemType value_type;
typedef ElemType *iterator;
typedef const ElemType *const_iterator;
typedef ElemType &reference;
typedef const ElemType &const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
private:
ElemType *buf;
size_type buf_size;
public:
alloca_array(void *alloca_buffer, size_t count)
: buf(NULL), buf_size(0)
{
buf = reinterpret_cast<ElemType *>(alloca_buffer);
for (size_t i = 0; i < count; ++i) {
new(&buf[i]) ElemType();
}
buf_size = count;
}
~alloca_array()
{
for (size_t i = buf_size; i-- > 0; ) {
buf[i].~ElemType();
}
}
reference operator[](size_t index)
{
return buf[index];
}
const reference operator[](size_t index) const
{
return buf[index];
}
iterator begin()
{
return &buf[0];
}
iterator end()
{
return &buf[count];
}
const_iterator begin() const
{
return &buf[0];
}
const_iterator end() const
{
return &buf[count];
}
// swap (note: linear complexity)
void swap (alloca_array<ElemType> &y) {
std::swap_ranges(begin(), end(), y.begin());
}
const ElemType* data() const
{
return buf;
}
ElemType *c_array()
{
return buf;
}
template <typename T2>
alloca_array<ElemType> &operator= (const alloca_array<T2> &rhs) {
std::copy(rhs.begin(), rhs.end(), begin());
return *this;
}
size_type size() const
{
return buf_size;
}
bool empty() const
{
return buf_size > 0;
}
reference at(size_type i)
{
rangecheck(i);
return buf[i];
}
const_reference at(size_type i) const
{
rangecheck(i);
return elems[i];
}
void rangecheck (size_type i) const
{
if (i >= buf_size) {
throw std::range_error("alloca_array<>: index out of range");
}
}
};
#endif // ALLOCA_ARRAY_H
--------------- alloca_array.hppここまで ---------------
テスト用コードを以下に。うまく動いてるみたいです。
--------------- aatest.cppここから ---------------
// allocatest
#include "alloca_array.hpp"
#include <string>
#include <cassert>
int main(int argc, char *argv[])
{
const int size = 100;
DECL_ALLOCA_ARRAY(astr, std::string, size);
astr[0] = "";
for (size_t i = 1; i < astr.size(); ++i) {
astr[i] = astr[i - 1] + std:: string("a");
}
for (size_t i = 0; i < astr.size(); ++i) {
assert(astr[i].length() == i);
}
DECL_ALLOCA_ARRAY(aint, int, size);
for (size_t i = 0; i < aint.size(); ++i) {
aint[i] = i;
}
for (size_t i = 0; i < astr.size(); ++i) {
assert(aint[i] == i);
}
return 0;
}
--------------- aatest.cppここまで ---------------
反省点と弱点
・プリプロセッサマクロを使っている。∵関数にするとスタックフレームが新たに作られてしまってallocaが役に立たないから。
・C99ではallocaなんか使わなくてもスタック上に配列を確保できるから、その機能を利用するようにarray.hppを修正したら、alloca_arrayは不要なのでは(お
(2005/09/28) 文字化けしていたので、いくつかの半角文字を全角文字で置換。orz
機能:
・スタック上に、動的にサイズが決定される配列を作る
(いったん作られた後は大きさを変更できない)。
・STLコンテナである。begin()やらend()やらが提供される。
--------------- alloca_array.hppここから ---------------
#if ! defined ALLOCA_ARRAY_H
#include <cassert>
#include <cstddef>
#if defined _MSC_VER
#include <malloc.h>
#define alloca _alloca
#elif defined _GCC
#include <alloca.h>
#else
#error "unsupported compiler"
#endif
#define DECL_ALLOCA_ARRAY(variable, ElemType, count) alloca_array<ElemType> variable(alloca(count * sizeof(ElemType)), (count))
template<typename ElemType>
class alloca_array {
public:
typedef ElemType value_type;
typedef ElemType *iterator;
typedef const ElemType *const_iterator;
typedef ElemType &reference;
typedef const ElemType &const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
private:
ElemType *buf;
size_type buf_size;
public:
alloca_array(void *alloca_buffer, size_t count)
: buf(NULL), buf_size(0)
{
buf = reinterpret_cast<ElemType *>(alloca_buffer);
for (size_t i = 0; i < count; ++i) {
new(&buf[i]) ElemType();
}
buf_size = count;
}
~alloca_array()
{
for (size_t i = buf_size; i-- > 0; ) {
buf[i].~ElemType();
}
}
reference operator[](size_t index)
{
return buf[index];
}
const reference operator[](size_t index) const
{
return buf[index];
}
iterator begin()
{
return &buf[0];
}
iterator end()
{
return &buf[count];
}
const_iterator begin() const
{
return &buf[0];
}
const_iterator end() const
{
return &buf[count];
}
// swap (note: linear complexity)
void swap (alloca_array<ElemType> &y) {
std::swap_ranges(begin(), end(), y.begin());
}
const ElemType* data() const
{
return buf;
}
ElemType *c_array()
{
return buf;
}
template <typename T2>
alloca_array<ElemType> &operator= (const alloca_array<T2> &rhs) {
std::copy(rhs.begin(), rhs.end(), begin());
return *this;
}
size_type size() const
{
return buf_size;
}
bool empty() const
{
return buf_size > 0;
}
reference at(size_type i)
{
rangecheck(i);
return buf[i];
}
const_reference at(size_type i) const
{
rangecheck(i);
return elems[i];
}
void rangecheck (size_type i) const
{
if (i >= buf_size) {
throw std::range_error("alloca_array<>: index out of range");
}
}
};
#endif // ALLOCA_ARRAY_H
--------------- alloca_array.hppここまで ---------------
テスト用コードを以下に。うまく動いてるみたいです。
--------------- aatest.cppここから ---------------
// allocatest
#include "alloca_array.hpp"
#include <string>
#include <cassert>
int main(int argc, char *argv[])
{
const int size = 100;
DECL_ALLOCA_ARRAY(astr, std::string, size);
astr[0] = "";
for (size_t i = 1; i < astr.size(); ++i) {
astr[i] = astr[i - 1] + std:: string("a");
}
for (size_t i = 0; i < astr.size(); ++i) {
assert(astr[i].length() == i);
}
DECL_ALLOCA_ARRAY(aint, int, size);
for (size_t i = 0; i < aint.size(); ++i) {
aint[i] = i;
}
for (size_t i = 0; i < astr.size(); ++i) {
assert(aint[i] == i);
}
return 0;
}
--------------- aatest.cppここまで ---------------
反省点と弱点
・プリプロセッサマクロを使っている。∵関数にするとスタックフレームが新たに作られてしまってallocaが役に立たないから。
・C99ではallocaなんか使わなくてもスタック上に配列を確保できるから、その機能を利用するようにarray.hppを修正したら、alloca_arrayは不要なのでは(お
(2005/09/28) 文字化けしていたので、いくつかの半角文字を全角文字で置換。orz