如果我有一个带有复制和移动构造函数的C ++类,并且复制赋值如下:
class Foo {
public:
int A[];
// custom ctor
Foo(size_t N) {
A = new A[N];
for(int i = 0; i < N; i++) A[i] = i * i;
}
// copy ctor
Foo(Foo& other) {
size_t N = sizeof(other.A) / sizeof(int);
A = new A[N];
for(int i = 0; i < N; i++) A[i] = other.A[i];
}
// move ctor
Foo(Foo&& other) {
A = other.A;
other.A = nullptr;
}
// copy assignment AND move assignment?
Foo& operator=(Foo other) {
std::swap(this.A, other.A);
return *this;
}
// default dtor
~Foo() {
delete[] A;
}
在这种情况下,我是否可以简单地避免定义移动赋值运算符并假设在可能的情况下仍然会进行移动分配?
我的理由是:复制赋值运算符必须构造定义为参数的Foo
对象。现在它可以在copy ctor和move ctor之间进行选择,因为两者都可用。因此,如果给定rvalue
它应该选择移动ctor,如果给出lvalue
,它应该选择复制ctor。这是对的吗?
另外:此实现是否适用于sizeof
数组的计算?如果没有,为什么不呢?
答案 0 :(得分:3)
建议:使用std::vector
问题:int A[];
是一个灵活的数组成员,它从与主对象相邻的额外内存中获取存储空间。您不能A = new int[N];
也不能sizeof (A)
。
修复:您可以使用int* A;
并自行跟踪大小,因为sizeof
指针与其指向的数组大小无关。
更好:std::vector<int>
会记住它的大小并实现析构函数,移动和复制操作,因此您不必这样做。
关于使用pass-by-value实现赋值的问题:是的,这是合法的,它甚至是一个成语:“复制和交换”。但是,它会在移动分配案例中导致不必要的额外移动,因此您可能希望直接实现它。或者不是,因为两个动作的成本几乎不会超过所需的动作。
如果使用std::vector
来存储数据,编译器生成的复制和移动操作将自动执行正确的操作。
答案 1 :(得分:0)
您始终无法定义移动ctor和赋值运算符。所有你将失去的是性能提升的机会。所以不,没有需要进行移动分配。
在您的情况下,此示例Foo f = Foo(); f = Foo()
您正在使用普通分配运算符,您可以在其中执行move
。你将在两个动作中加上swap
。
关于你 EDIT:,但VLA除外,它执行运行时检查,因此它是正确的。sizeof
问题,它无法正常工作。 sizeof
将返回指针类型的大小,这是常量