问题
In C++11, there are two versions of std::vector::resize()
:
void resize( size_type count );
void resize( size_type count, const value_type& value);
I understand (as suggested by one of the comments to one of the answers to this question) that the first requires value_type
to be default constructible, while the second requires it to be copy constructible. However, (gcc 4.7.0)
using namespace std;
typedef int block[4];
vector<block> A;
static_assert(is_default_constructible<block>::value,";-("); // does not fire
A.resize(100); // compiler error
So either my understanding was wrong or gcc is buggy. Which?
回答1:
The requirement (23.3.6.3:10) on vector.resize(n)
being well-formed is that T
should be CopyInsertable
, i.e. that the following should be well-formed (23.2.1:13):
allocator_traits<A>::construct(m, p, v);
where A
is the allocator type of the vector, m
is the allocator, p
is of type T *
and v
is of type T
.
As you can discover from 20.6.8.2:5, this is invalid for array types in the general case as it is equivalent to calling
::new(static_cast<void *>(p))block(v);
which is invalid for array types (arrays cannot be initialized by parentheses).
Actually, you're correct that g++ has a bug; it should always be possible to work around the issue with CopyInsertable
by providing an appropriate allocator, but g++ fails to allow this:
#include <vector>
template<typename T, int n> struct ArrayAllocator: std::allocator<T[n]> {
void construct(T (*p)[n], T (&v)[n]) {
for (int i = 0; i < n; ++i)
::new(static_cast<void *>(p + i)) T{v[i]};
}
};
int main() {
std::vector<int[4], ArrayAllocator<int, 4>> c;
c.resize(100); // fails
typedef ArrayAllocator<int, 4> A;
A m;
int (*p)[4] = 0, v[4];
std::allocator_traits<A>::construct(m, p, v); // works
}
Another bug is in the standard itself; 20.9.4.3:3 specifies std::is_default_constructible<T>
as equivalent to std::is_constructible<T>
, where 20.9.4.3:6 specifies std::is_constructible<T, Args...>
as the well-formedness criterion on T t(std::declval<Args>()...)
, which is valid for array types (as @Johannes Schaub-litb points out, array types can be initialised with (zero-pack-expansion)
). However, 17.6.3.1:2 requires for DefaultConstructible
in addition that T()
be well-formed, which is not the case for an array type T
but is not checked by std::is_default_constructible
.
回答2:
I found this discussion after I ran into a similar problem with resize() not working for a default-constructible type. It seems like the gcc vector implementation is incorrect.
FYI, I filed a bug against gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64147
来源:https://stackoverflow.com/questions/12192895/should-in-c11-stdvectorresizesize-type-work-for-the-default-constructi