如何使用自定义分配器而不是复制构造函数来调整std :: vector的大小?
以下是我的尝试:
#include <vector>
#include <iostream>
class A{
public:
A(int x){
std::cout<<" new a:"<<this<<" "<< x<<std::endl;
}
};
template<typename T>
class ParamAlloc:public std::allocator<T>{
public:
template<typename U> struct rebind {typedef ParamAlloc other;};
void construct(typename std::allocator<T>::pointer p, typename std::allocator<T>::const_reference val){
new ((void*)p) T(47);
}
void destroy(typename std::allocator<T>::pointer p){
((T*)p)->~T();
}
};
int main(){
ParamAlloc<A> all;
std::vector<A,ParamAlloc<A> > ac(all);
ac.resize(5);
}
但由于编译尝试实例化A :: A(),我仍然遇到编译错误。
与此问题相关,分配A类对象向量的最佳方法(前C ++ 11)是什么,其中A的构造函数采用参数,但A对象不应复制构造
答案 0 :(得分:3)
Pre-C ++ 11 resize
成员定义为:
resize(size_type n, const T& = T());
因此,当您将其称为ac.resize(5)
时,实际上意味着ac.resize(5, A())
显然需要默认构造函数。 C ++ 03的唯一解决方法是提供一个要复制的对象:ac.resize(5, A(99))
,它表示调整向量的大小并将任何新元素构造为A(99)
的副本。副本将由您的自定义分配器完成,它实际上将它们构造为A(47)
,而不是使用复制构造函数。
C ++ 11放宽了对resize()
的要求,而[vector.capacity]中的C ++ 11标准说vector::resize()
要求:
T
应为MoveInsertable
且DefaultInsertable
为*this
。
DefaultInsertable
要求这是有效的:
allocator_traits<A>::construct(m, p)
该调用将尝试在分配器m.construct(p)
上调用m
,如果该调用有效,但是因为您的分配器不支持它将执行:
::new((void *)p) T()
需要默认构造函数。
如果您希望将自定义分配器用于resize
,则需要提供一个只能使用一个参数调用的construct
成员,例如
void construct(typename std::allocator<T>::pointer p){
new ((void*)p) T(47);
}
这应该意味着在调整大小时不需要默认构造函数。
答案 1 :(得分:0)
只需为A(int x)
提供默认参数,该组合将通过。
class A{
public:
A(int x=0){//here !!
std::cout<<" new a:"<<this<<" "<< x<<std::endl;
}
};
结果是:
new a:0x7fffe01aab5f 0
new a:0x1c7d010 47
new a:0x1c7d011 47
new a:0x1c7d012 47
new a:0x1c7d013 47
new a:0x1c7d014 47
答案 2 :(得分:0)
C ++标准定义了给定容器的项类型的某些要求。
例如,可以在C ++ 11 T must meet the requirements of CopyAssignable and CopyConstructible之前的向量中存储。要调整大小,请T must meet the requirements of DefaultConstructible。因此,前C ++ 11标准明确禁止您尝试实现的目标。也许你使用vector::reserve
代替vector::resize
就足够了,或者你只需要一个不同的容器。这在C ++ 11中是可能的 - 请参阅Jonathan Wakely的回答。