Questions:
- What is the slight deviation from the standard interface in the explicit Vector(size_type capacity)? Is it that the param is named 'capacity' and not 'count?
If you look at the standard (I link to a non standard but reputable source) std::vector::vector you will see there is no constructor that takes a "capacity" (ie. you have allocated space but zero size). There is one that takes a size and fills it with values (but you have that one).
- When you say "T()" should be in the header only, do you mean the template declaration?
No. Default Parameters should be defined in the class header file only. They are not part of the declaration:
class Vector
{
void resize(size_type count, const_reference value = T());
// This is good.
// Reading the interface you see you can have a default value.
};
// Don't define the default parameters here.
// It should generate an error if you do this.
void Vector::resize(size_type count, const_reference value)
{
// STUFF
}
- How does constructing the item in place in push_back() resolve the uninitialized memory issue?
This is a problem becasue:
// This code uses the assignment operator.
data[m_size++] = item;
// The assignment operator assumes that the object
// referenced on the left hand side has already been constructed
// but in your case that is not true, this is unintialized memory.
// So you are using assignment to uninitialized memory
// which could be anything and thus with non trivial T
// will cause an issue.
This is solved by constructing in place:
// Should be this.
new (std::addressof(data[m_size++])) T(item);
The constructor assumes the memory has not been constructed before. You pass the address to operator new it will not allocate space but simply use the pointer provided as the location and then call the constructor for the type T to correctly initialize the memory.
- do you have any references or documentation on the "pass by value" idiom for avoiding the two assignment operators?
Nope. There are lots of questions on Stackoverflow that go over this though. Should be simple to find.
- And does the SFINAE approach involve checking std::is_nothrow_move_constructible or something in overload resolution? I should look into how this is done in some compiler implementation
Yep.