一个通用的解决方案是让您的向量采用自定义分配器,其construct
方法执行适当的初始化。在下面的代码中,v
使用MyAllocator<NonMovable>
分配器而不是std::allocator<NonMovable>
. 当construct
不带参数调用该方法时,它实际上是使用适当的参数调用构造函数。这样,默认构造函数就可以正确初始化元素。
(简单地说,我在这个例子中设置了静态,但它也可以是一个在构造next_value
时初始化的非静态成员变量。)MyAllocator
#include <stdio.h>
#include <memory>
#include <new>
#include <vector>
struct NonMovable {
NonMovable(int x) : x(x) {}
const int x;
};
template <class T>
struct MyAllocator {
typedef T value_type;
static int next_value;
T* allocate(size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
::operator delete(p);
}
template <class U>
void construct(U* p) {
new (p) U(++next_value);
}
};
template <class T> int MyAllocator<T>::next_value = 0;
int main() {
std::vector<NonMovable, MyAllocator<NonMovable>> v(10);
for (int i = 0; i < 10; i++) {
printf("%d\n", v[i].x);
}
}
http://coliru.stacked-crooked.com/a/1a89fddd325514bf
当您不允许触摸NonMovable
类并且其构造函数可能需要多个参数时,这是唯一可能的解决方案。在您只需要向每个构造函数传递一个参数的情况下,有一个更简单的解决方案,它使用 的范围构造函数std::vector
,如下所示:
std::vector<int> ints(10);
std::iota(ints.begin(), ints.end(), 1);
std::vector<NonMovable> v(ints.begin(), ints.end());
(虽然如果你负担不起额外的内存,那么你将不得不编写一个自定义迭代器,这将是更多的代码。)