I am creating a templated Vector class, however, when comparing its use to something such as std::vector, I noticed that it does not allow structs\classes without a default (emtpty) constructor. The error I will get is
error C2512: 'SomeStruct' : no appropriate default constructor available
: while compiling class template member function 'Vector<Type>::Vector(void)'
: see reference to class template instantiation 'Vector<Type>' being compiled
However, if I were to go and use std::vector, this would be allowed. Here is my test case
struct SomeStruct
{
SomeStruct(int a){}
};
template<typename Type>
class Vector
{
public:
Vector();
protected:
Type* m_Data;
unsigned int m_Count;
unsigned int m_Capacity;
};
template<typename Type>
Vector<Type>::Vector()
{
m_Capacity = 0;
m_Count = 0;
m_Data = new Type[m_Capacity];
}
void main()
{
Vector<SomeStruct> test1;
}
How can I allow my templated Vector allow types without a default (empty) constructor?
(I know I could just use std::vector, but I am doing this to learn more about the language, and to run into cases like this)
The reason why this doesn’t work for types without default constructors is because of this line:
The above line fundamentally does two things: allocate enough memory to hold
m_Capacityinstances ofType, then constructing eachTypeso that they’re ready to use. Since you can’t actually provide any constructor arguments through thisnew[]syntax, default constructors are required when you use this.The way
std::vector(and the other standard containers) deals with this is by separating the memory allocation process and the construction process. That is,std::vectoramortizes the cost of memory allocation by requesting large chunks of memory with “nothing” in it. Thenstd::vectoruses placementnewto construct objects directly in that memory.So something like this might be going on inside a
std::vector:So what’s going on here is that our hypothetical
Vectorclass allocates a relatively large slab of memory, then as items are pushed or inserted, the class does placement new in the memory. So this eliminates the default constructor requirement, since we don’t actually construct any objects unless requested by the caller.As you can already see, a
std::vectorclass needs to do quite a bit of bookkeeping to make what it does efficient and safe. That’s why we urge people to use the standard containers instead of rolling out your own, unless you really know what you’re doing. Making an efficient, safe, and useful vector class is a huge undertaking.For an idea of what’s involved, take a look at a paper called “Exception Safety: Concepts and Techniques” by Bjarne Stroustrup which discusses a “simple vector” implementation (section 3.1). You’ll see that it’s not a trivial thing to implement.