11

在 C++11 中,有两个版本std::vector::resize()

void resize( size_type count );
void resize( size_type count, const value_type& value);

我理解(正如对此问题的其中一个答案的评论之一所建议的那样)第一个要求value_type是默认可构造的,而第二个要求它是可复制构造的。但是,(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

所以要么我的理解是错误的,要么 gcc 有问题。哪个?

4

2 回答 2

10

vector.resize(n)格式良好的要求 (23.3.6.3:10)T应该是CopyInsertable,即以下内容应该是格式良好的 (23.2.1:13):

allocator_traits<A>::construct(m, p, v);

其中A是向量的分配器类型,m是分配器,p是类型T *v是类型T

正如您从 20.6.8.2:5 中发现的那样,这在一般情况下对数组类型无效,因为它等效于调用

::new(static_cast<void *>(p))block(v);

这对数组类型无效(数组不能用括号初始化)。


实际上,您是正确的 g++ 有一个错误;CopyInsertable通过提供适当的分配器应该总是可以解决这个问题,但是 g++ 不允许这样做:

#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
}

另一个错误在于标准本身。20.9.4.3:3 指定std::is_default_constructible<T> 为等效于std::is_constructible<T>,其中 20.9.4.3:6 指定std::is_constructible<T, Args...>为 上的良构性标准T t(std::declval<Args>()...),这对数组类型有效(正如@Johannes Schaub-litb 指出的那样,数组类型可以用 初始化(zero-pack-expansion))。但是,17.6.3.1:2 还要求格式正确DefaultConstructibleT()数组类型并非如此,Tstd::is_default_constructible.

于 2012-08-30T08:49:12.967 回答
0

在遇到 resize() 不适用于默认可构造类型的类似问题后,我发现了这个讨论。似乎 gcc 向量实现不正确。

仅供参考,我针对 gcc 提交了一个错误: https ://gcc.gnu.org/bugzilla/show_bug.cgi?id=64147

于 2014-12-02T08:22:47.823 回答