C风格数组的标准容器
std container for C-style array
是否有用于大小可变的 C 样式数组的 std 容器?
比如我有下面的代码
int size = 5; // This is not a constant in general
int *my_array = SpecialAllocationFunction(size);
我希望能够使用 C++ 标准样式容器访问此数组。具有迭代器和函数的东西,例如:size
、begin
、end
、...
我知道如果 my_array
的大小不变,我可以使用 std::array
。我自己也可以写一个,但我觉得一定有现成的。
正如@NathanOliver 和@utnapistim 在评论中所说,gsl::span
有效。因为我不想包含这个库,所以我最终自己写了一个 "trivial wrapper"。下面包括其他寻找答案的人(和我未来的自己)
template<class T>
class span {
public:
inline span() : _data(0), _size(0) {}
inline span(T* d, size_t s) : _data(d), _size(s) {}
inline T& operator[](size_t index) { return _data[index]; }
inline const T& operator[](size_t index) const { return _data[index];}
inline size_t size() const { return _size; };
inline T* begin() { return _data; }
inline const T* begin() const { return _data; }
inline T* end() { return _data+_size; }
inline const T* end() const { return _data+_size; }
protected:
T* _data;
size_t _size;
};
使用自定义分配器,可以构建一个向量,其大小仅在 运行 时已知(因此 std::array
不可能),包装现有数组。甚至可以通过覆盖特殊的 construct
方法 (*).
来保留 pre-existing 值
这是一个可能的实现:
/**
* a pseudo allocator which receives in constructor an existing array
* of a known size, and will return it provided the required size
* is less than the declared one. If keep is true in contructor,
* nothing is done at object construction time: original values are
* preserved
* at deallocation time, nothing will happen
*/
template <class T>
class SpecialAllocator {
T * addr;
size_t sz;
bool keep;
public:
typedef T value_type;
SpecialAllocator(T * addr, size_t sz, bool keep):
addr(addr), sz(sz), keep(keep) {}
size_t max_size() {
return sz;
}
T* allocate(size_t n, const void* hint=0) {
if (n > sz) throw std::bad_alloc(); // throws a bad_alloc...
return addr;
}
void deallocate(T* p, size_t n) {}
template <class U, class... Args>
void construct(U* p, Args&&... args) {
if (! keep) {
::new((void *)p) U(std::forward<Args>(args)...);
}
}
template <class U>
void destroy(U* p) {
if (! keep) {
p->~U(); // do not destroy what we have not constructed...
}
}
};
然后可以这样使用:
int size = 5; // This is not a constant in general
int *my_array = SpecialAllocationFunction(size);
SpecialAllocator<int> alloc(my_array, size);
std::vector<int, SpecialAllocator<int> > vec(size, alloc);
从那时起,vec
将是一个真正的 std::vector
包装 my_array
。
这是一个简单的演示代码:
int main(){
int arr[5] = { 5, 4, 3, 2, 1 };
SpecialAllocator<int> alloc(arr, 5, true); // original values will be preserved
std::vector<int, SpecialAllocator<int> > vec(5, alloc);
for(auto it= vec.begin(); it != vec.end(); it++) {
std::cout << *it << " ";
}
std::cout << std::endl;
try {
vec.push_back(8);
}
catch (std::bad_alloc& a) {
std::cout << "allocation error" << std::endl;
}
return 0;
}
会成功输出:
5 4 3 2 1
allocation error
(*) 注意: Construction/destruction 可能涉及不同的地方:push_back
, emplace_back
,等等。在使用 no-op construct
和 destroy
方法之前,请仔细考虑您的实际用例。
是否有用于大小可变的 C 样式数组的 std 容器? 比如我有下面的代码
int size = 5; // This is not a constant in general
int *my_array = SpecialAllocationFunction(size);
我希望能够使用 C++ 标准样式容器访问此数组。具有迭代器和函数的东西,例如:size
、begin
、end
、...
我知道如果 my_array
的大小不变,我可以使用 std::array
。我自己也可以写一个,但我觉得一定有现成的。
正如@NathanOliver 和@utnapistim 在评论中所说,gsl::span
有效。因为我不想包含这个库,所以我最终自己写了一个 "trivial wrapper"。下面包括其他寻找答案的人(和我未来的自己)
template<class T>
class span {
public:
inline span() : _data(0), _size(0) {}
inline span(T* d, size_t s) : _data(d), _size(s) {}
inline T& operator[](size_t index) { return _data[index]; }
inline const T& operator[](size_t index) const { return _data[index];}
inline size_t size() const { return _size; };
inline T* begin() { return _data; }
inline const T* begin() const { return _data; }
inline T* end() { return _data+_size; }
inline const T* end() const { return _data+_size; }
protected:
T* _data;
size_t _size;
};
使用自定义分配器,可以构建一个向量,其大小仅在 运行 时已知(因此 std::array
不可能),包装现有数组。甚至可以通过覆盖特殊的 construct
方法 (*).
这是一个可能的实现:
/**
* a pseudo allocator which receives in constructor an existing array
* of a known size, and will return it provided the required size
* is less than the declared one. If keep is true in contructor,
* nothing is done at object construction time: original values are
* preserved
* at deallocation time, nothing will happen
*/
template <class T>
class SpecialAllocator {
T * addr;
size_t sz;
bool keep;
public:
typedef T value_type;
SpecialAllocator(T * addr, size_t sz, bool keep):
addr(addr), sz(sz), keep(keep) {}
size_t max_size() {
return sz;
}
T* allocate(size_t n, const void* hint=0) {
if (n > sz) throw std::bad_alloc(); // throws a bad_alloc...
return addr;
}
void deallocate(T* p, size_t n) {}
template <class U, class... Args>
void construct(U* p, Args&&... args) {
if (! keep) {
::new((void *)p) U(std::forward<Args>(args)...);
}
}
template <class U>
void destroy(U* p) {
if (! keep) {
p->~U(); // do not destroy what we have not constructed...
}
}
};
然后可以这样使用:
int size = 5; // This is not a constant in general
int *my_array = SpecialAllocationFunction(size);
SpecialAllocator<int> alloc(my_array, size);
std::vector<int, SpecialAllocator<int> > vec(size, alloc);
从那时起,vec
将是一个真正的 std::vector
包装 my_array
。
这是一个简单的演示代码:
int main(){
int arr[5] = { 5, 4, 3, 2, 1 };
SpecialAllocator<int> alloc(arr, 5, true); // original values will be preserved
std::vector<int, SpecialAllocator<int> > vec(5, alloc);
for(auto it= vec.begin(); it != vec.end(); it++) {
std::cout << *it << " ";
}
std::cout << std::endl;
try {
vec.push_back(8);
}
catch (std::bad_alloc& a) {
std::cout << "allocation error" << std::endl;
}
return 0;
}
会成功输出:
5 4 3 2 1
allocation error
(*) 注意: Construction/destruction 可能涉及不同的地方:push_back
, emplace_back
,等等。在使用 no-op construct
和 destroy
方法之前,请仔细考虑您的实际用例。