C++ std::vector<;的类型要求;类型>;

C++ std::vector<;的类型要求;类型>;,c++,constructor,c++11,allocation,stdvector,C++,Constructor,C++11,Allocation,Stdvector,我仍然对C++11中与std::vector一起使用的类型的要求感到困惑,但这可能是由错误的编译器(GCC4.7.0)造成的。此代码: struct A { A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; } int X; }; int main() { std::vector<A> a; a.resize(4); } 结构A{ A():X(0){std::cerr要在

我仍然对C++11中与
std::vector
一起使用的类型的要求感到困惑,但这可能是由错误的编译器(GCC4.7.0)造成的。此代码:

struct A {
  A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
  int X;
};

int main()
{
  std::vector<A> a;
  a.resize(4);
}
结构A{
A():X(0){std::cerr要在向量中使用类,它应该有一个复制构造函数/赋值运算符或一个noexcept移动构造函数/赋值运算符。GCC不编译没有这些运算符的示例是非常正确的

除了向量之外,你如何在不能复制或移动它包含的内容的情况下做任何事情

第一个示例工作的原因是,由于您没有定义任何复制或移动构造函数或赋值运算符,因此得到了默认值。在第二个示例中,由于您显式删除了复制构造函数,因此没有得到任何自动生成的构造函数或赋值运算符。

,我看到一个对默认构造函数的调用构造器。但是要创建四个对象,其他对象必须以某种方式构造。实际上,一个原型对象是默认构造的,然后复制四次

C++11标准(第23.3.6.3节)规定将插入“值初始化”对象,但也要求类型可复制:

void resize(大小_-type sz);


  • 效果:在C++11中,如果
    sz,则要求取决于执行的操作。在
    std::vector::resize()
    的情况下,
    T
    的要求是将其放入向量中

    从§23.3.6.3开始

    void resize(大小_-type sz);

    要求:
    T
    应可
    CopyInsertable
    插入*中

    void resize(size\u type)
    需要
    CopyInsertable
    ,这意味着分配器应该能够构造复制类型:

    ::new((void*)p)A(A());
    
    这意味着需要一个复制构造函数。您应该能够使用自定义分配器绕过该构造函数:

    struct Allocator: public std::allocator<A> {
      void construct(A *, const A &) { }
    };
    
    struct Allocator:public std::Allocator

    正如其他人所指出的,C++11标准确实需要
    CopyInsertable
    。然而,这是C++11标准中的一个缺陷。这已在
    MoveInsertable
    DefaultInsertable
    中得到纠正

    vector::resize(n)
    成员函数需要
    MoveInsertable
    DefaultInsertable
    。当分配器
    A
    使用默认
    construct
    定义时,这些函数大致转换为
    DefaultConstructible
    MoveConstructible

    以下程序使用clang/libc++编译:

    #include <vector>
    #include <iostream>
    
    struct A {
      A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
      A(A&&) = default;
      int X;
    };
    
    int main()
    {
      std::vector<A> a;
      a.resize(4);
    }
    

    如果您删除上面的移动构造函数并将其替换为已删除的副本构造函数,
    a
    不再是作为移动构造函数的
    MoveInsertable
    /
    MoveConstructible
    ,然后尝试使用已删除的副本构造函数,如OP的问题中正确所示。

    请详细说明“预期输出”.产生了多少行输出?Ben,有趣的是,我的输出与您在ideone上使用gcc 4.5.4得到的输出不同:我得到:
    A::A(),这个=0x603010 A::A(),这个=0x603014 A::A(),这个=0x603018 A::A()在这个=0x60301c
    上,即默认的ctor被调用4次,而不是一次,然后从中复制对象。这是一个显著的区别……但是,这可能是一个规范缺陷。请注意,只需要一个大小的
    向量
    构造函数只需要
    DefaultConstructible
    。没有理由
    调整大小
    需要
    CopyInsertable
    ;只需要
    DefaultConstructible
    以及可能需要的任何重新分配。@Nicolas这么说你是在暗示gcc有缺陷吗?@Walter:规范缺陷不是软件中的缺陷。它是规范中的缺陷。这实际上是错误的。删除副本构造函数应该不会对赋值运算符产生任何影响,而是d该类有一个用户定义的默认构造函数。+1表示移动构造函数。事实上,如果我给出它(使用
    =default
    )但是
    delete
    copy-ctor,它工作正常!编辑我将您的赋值运算符重新解释为构造函数,以纠正您的错误。@juanchopanza删除copy-ctor确实会阻止生成移动赋值运算符。由于遗留原因,它会保留copy-assignment运算符,但任何使用它的程序都非常可疑。但是你声称你没有得到自动生成的赋值运算符是不正确的。你得到了一个复制赋值运算符,不管它是否有意义。为什么不
    ::new((void*)p)a();
    而不是
    ::new((void*)p)a(a();
    ,我不明白
    a(a())
    a()
    …@PiotrNycz,它来自复制构造的默认实现
    迭代器特征::construct
    。但是请注意,libstdc++不尊重分配器模板参数;请参阅我的答案。我有相同的输出,但仍然很困惑,因为每个对象都调用默认的ctor。因此,move ctor似乎不是c已全部调用。请注意,如果将move ctor替换为copy ctor,结果将保持不变:它从未被调用,但是
    std::vector::resize()
    的实现所必需的。我在上一次投票中对ecatmur对您的问题的正确回答投了赞成票。我怀疑,只要避免调用
    resize(),没有默认的ctor是可以的
    。还要注意,如果计划使用向量填充构造函数,则有必要提供一个复制构造函数:
    std::vector a(10,a());
    #include <vector>
    #include <iostream>
    
    struct A {
      A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
      A(A&&) = default;
      int X;
    };
    
    int main()
    {
      std::vector<A> a;
      a.resize(4);
    }
    
     A::A(); this=0x7fcd634000e0
     A::A(); this=0x7fcd634000e4
     A::A(); this=0x7fcd634000e8
     A::A(); this=0x7fcd634000ec