我仍然对在C ++ 11中与std::vector
使用的类型的要求感到困惑,但这可能是由错误的编译器(gcc 4.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);
}
工作正常并产生预期的输出,表明默认的ctor(显式给定)被调用(而不是隐式复制ctor)。但是,如果我将删除的副本ctor添加到班级,即
struct A {
A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
A(A const&) = delete;
int X;
};
gcc 4.7.0无法编译,但尝试使用已删除的ctor。这是正确的行为还是错误?如果是前者,如何让代码工作?
答案 0 :(得分:13)
正如其他人所指出的那样,C ++ 11标准确实需要 CopyInsertable
。但是,这是C ++ 11标准中的一个错误。此后已在N3376至MoveInsertable
和DefaultInsertable
中进行了更正。
vector<T, A>::resize(n)
成员函数需要MoveInsertable
和DefaultInsertable
。当分配器DefaultConstructible
使用默认的MoveConstructible
定义时,这些大致会转换为A
和construct
。
以下程序使用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::A(); this=0x7fcd634000e0
A::A(); this=0x7fcd634000e4
A::A(); this=0x7fcd634000e8
A::A(); this=0x7fcd634000ec
如果删除上面的移动构造函数并将其替换为已删除的复制构造函数,则A
不再是MoveInsertable
/ MoveConstructible
,因为移动构造会尝试使用已删除的复制构造函数,正如在OP的问题中正确证明的那样。
答案 1 :(得分:3)
在C ++ 11中,要求取决于所执行的操作。对于std::vector<T>::resize()
,T
的要求是向量CopyInsertable
。
来自§23.3.6.3
void resize(size_type sz);
...
要求:
T
应为CopyInsertable
*此。
答案 2 :(得分:2)
要在向量中使用类,它应该具有复制构造函数/赋值运算符或noexcept移动构造函数/赋值运算符。 GCC完全没有编译你没有任何这些的例子。
除了矢量之外你怎么做才能复制或移动它包含的内容?
第一个示例有效的原因是,由于您没有定义任何副本或移动构造函数或赋值运算符,因此您将获得默认值。在第二个示例中,由于您显式删除了复制构造函数,因此您不会获得任何自动生成的构造函数或赋值运算符。
答案 3 :(得分:2)
On ideone,我看到对默认构造函数的一次调用。但是正在创建四个对象,其他对象必须以某种方式构建。实际上,默认构造原型对象然后复制四次。
C ++ 11标准(第23.3.6.3节)说将插入“值初始化”对象,但也要求该类型是可复制的:
void resize(size_type sz);
- 效果:如果
sz <= size()
,相当于erase(begin() + sz, end());
。如果size() < sz
,请将sz - size()
值初始化元素附加到序列中。- 要求:
T
CopyInsertable
为*this
。
这里没有编译错误;这是你的代码错了。
答案 4 :(得分:1)
void resize(size_type)
需要CopyInsertable
,这意味着分配器应该能够构造 - 复制类型:
::new((void*)p)A(A());
这意味着需要复制构造函数。您应该可以使用自定义分配器绕过它:
struct Allocator: public std::allocator<A> {
void construct(A *, const A &) { }
};
然而libstdc ++并不尊重这一点;见Should (in C++11) std::vector::resize(size_type) work for the default constructible value_type int[4]?