问题 应该(在C ++ 11中)std :: vector :: resize(size_type)是否适用于默认的可构造的value_type int [4]?


在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是错误的。哪一个?


9594
2017-08-30 08:33


起源

使用此块定义: struct block { int arr[4]; }; - PiotrNycz
可能重复 C ++ std :: vector of array的编译器错误 - Nicol Bolas
@PiotrNycz:相对于 std::array<int, 4>? - ildjarn
@ildjarn为什么反对?它或多或少是相同的...由于我的工作“糟糕的条件”我仍然在C ++ 03 - 所以我仍在思考C ++ 03;) - PiotrNycz


答案:


要求(23.3.6.3:10) vector.resize(n) 形式良好的是 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 ++有一个bug;应始终可以解决这个问题 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要求 DefaultConstructible 另外那个 T() 形式良好,而不是数组类型的情况 T 但未经过检查 std::is_default_constructible


10
2017-08-30 08:49



有人应该在这里提交错误报告。 - Walter
首先,我没理解你的 T t()。我想重要的是要提到它是一个结果 T t(zero pack expansion)。否则,“变量定义上下文”很难看出你的意思。但 T t(zero pack expansion)  是 如果有效 T 是一个数组类型,元素类型可以初始化值。只要 T() 如果,是不正确的 T 是一种数组类型。 - Johannes Schaub - litb
@ JohannesSchaub-litb谢谢,看起来这部分是标准定义中的一个bug std::is_default_constructible。 - ecatmur
我问过daniel kruegler,他说他已经开始研究类似物了(修正了聚合物的DefaultConstrictible定义)。他同意我的观点,这种特性的结果更令人期待,并且该语言可能应该被修改为允许 ArrayType()(特别是从 ArrayType{} 是允许的。)我相信他采取了适当的行动。 - Johannes Schaub - litb


我遇到类似的问题后发现了这个讨论,resize()不适用于default-constructible类型。似乎gcc向量实现是不正确的。

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


0
2017-12-02 08:22