对于嵌入式系统,我们需要一个自定义向量类,其中通过模板参数在编译期间设置容量。
到目前为止,我们有一个对象数组作为成员变量。
template<class T, size_t SIZE>
class Vector {
...
T data[SIZE];
}
这里的问题当然是如果T不是POD,则调用T的默认构造函数。有没有办法让数据在相应的push()调用之前保持未初始化(内置新的放置)?只是使用
uint8_t data[SIZE * sizeof(T)];
可能会破坏T的对齐。我们绝对不能使用动态内存,总容器大小总是需要在编译时知道。我们也不能使用C ++的alignas说明符,因为编译器还不支持C ++ 11 :(
答案 0 :(得分:1)
您将不得不使用展示位置// use `std::max_align_t` and `std::aligned_storage` when you have it
// since don't have access to alignof(), use the presumably max
// alignment value
using MaxAlign = long;
template <typename T, int size>
class UninitializedArray {
union Node {
char data[sizeof(T)];
MaxAlign alignment;
};
Node aligned_data[size];
bool initialized;
public:
UninitializedArray() : initialized(false) {}
void initialize() {
for (int i = 0; i < static_cast<int>(size); ++i) {
new (&this->aligned_data[i].data) T();
}
this->initialized = true;
}
~UninitializedArray() {
if (this->initialized) {
for (int i = 0; i < static_cast<int>(size); ++i) {
T* ptr = reinterpret_cast<T*>(&this->aligned_data[i].data);
ptr->~T();
}
}
}
T& operator[](int index) {
if (!this->initialized) {
this->initialize();
}
T* ptr = reinterpret_cast<T*>(&this->aligned_data[i].data);
return *ptr;
}
};
以及联合技巧来正确设置对齐方式。
UninitializedArray<Something, 5> arr;
arr[0].do_something();
然后像这样使用它
std::array
如果你让C ++ 17正常工作,那么你可以使用std::optional
和std::optional<std::array<T, N>> optional_array;
// construct the optional, this will construct all your elements
optional_array.emplace();
// then use the value in the optional by "treating" the optional like
// a pointer
optional_array->at(0); // returns the 0th object
来实现这一目标
{gridColumn: '1 / 3', gridRow: '2 / 5', gridArea: 'header'}
答案 1 :(得分:1)
首先我会检查编译器是否支持对齐,即gcc有__attribute__(aligned(x))
,可能有类似的东西。
然后,如果你必须在没有这种支持的情况下对齐未初始化的数据,你将不得不浪费一些空间
// Align must be power of 2
template<size_t Len, size_t Align>
class aligned_memory
{
public:
aligned_memory()
: data((void*)(((std::uintptr_t)mem + Align - 1) & -Align)) {}
void* get() const {return data;}
private:
char mem[Len + Align - 1];
void* data;
};
你可以使用新的随附
template<typename T, size_t N>
class Array
{
public:
Array() : sz(0) {}
void push_back(const T& t)
{
new ((T*)data.get() + sz++) T(t);
}
private:
aligned_memory<N * sizeof(T), /* alignment */> data;
size_t sz;
};
可以在C ++ 11 T
中找到alignof
的对齐方式,检查编译器是否支持可用于找出其对齐方式的任何内容。您也可以从打印的指针值中猜测,并希望这足够了。
答案 2 :(得分:1)
另一种方法是将std::vector<>
与在堆栈上分配的自定义分配器一起使用。
这样你就可以创建一个空向量,保留所需的空间,该空间应该等于你的分配器在堆栈上为你分配的空间,然后使用vector<>::emplace_back
填充向量。您的元素类型可以是不可复制的,但在这种情况下必须是可移动的。
E.g:
#include <vector>
struct X {
X(int, int);
// Non-copyable.
X(X const&) = delete;
X& operator=(X const&) = delete;
// But movable.
X(X&&);
X& operator=(X&&);
};
template<class T, std::size_t N>
struct MyStackAllocator; // Implement me.
int main() {
std::vector<X, MyStackAllocator<X, 10>> v;
v.reserve(10);
v.emplace_back(1, 2);
v.emplace_back(3, 4);
}
有关如何实施分配器的信息广泛可用,例如,在YouTube上搜索&#34; c ++分配器&#34;。