提问人:Nolazuck 提问时间:4/21/2022 更新时间:4/21/2022 访问量:168
如何禁用从派生类移动构造基类?
how to disable move construct base class from derived class?
问:
在下面的代码中,我想从派生类中禁用基类的移动构造,并调用复制构造函数。Vector
VectorMap
#include <iostream>
#include<algorithm>
struct Vector{
int* _ptr=nullptr;
int _size=0;
Vector(int n){
_ptr = new int[n];
_size = n;
std::cout<< " Construct "<<this<<std::endl;
}
Vector(void) { std::cout <<" Construct " << this << std::endl; }
virtual ~Vector(void) {
if (_ptr != nullptr) {
std::cout << "Deconstruct " << this << " -> delete " << _ptr << std::endl;
delete _ptr;
return;
}
std::cout << "Deconstruct " << this << std::endl;
}
Vector(Vector&& v2) noexcept {
int* p2=v2._ptr; int s2=v2._size;
v2._ptr=_ptr;
v2._size=_size;
_ptr=p2; _size=s2;
std::cout << "Move construct " << this << std::endl;
}
Vector(const Vector& v3){
_ptr=new int[v3._size];
_size=v3._size;
memcpy(_ptr,v3._ptr,sizeof(int) * _size);
}
};
struct VectorMap
: public Vector {
VectorMap(int* p,int size){
_ptr=p;
_size=size;
}
~VectorMap(void) override {
_ptr=nullptr; _size=0;
}
};
int main(void) {
Vector v1(10);
Vector v2=VectorMap(v1._ptr,5); // v1._ptr will be deleted twice
return sizeof(v2);
}
如您所见,如果在行中调用 move 构造函数,则 中的数据指针将被删除两次,一次是 ,另一次是 。因为它们共享相同的指针。在这种情况下,有没有办法修改为调用复制构造函数而不是移动构造函数?Vector v2=VectorMap(v1._ptr,5);
v1
v2
v1
VectorMap
答:
主要问题是所有权语义混乱。
Vector
创建一个资源(动态数组),并且显然旨在对其拥有唯一的所有权。
VectorMap
另一方面,在其构造函数中获取指针,并将其提供给获取所有权的基础。但在销毁之前,通过将基指针设置为 null 来撤销所有权。因此,在某种程度上假装拥有资源,直到所有权的责任到来,这时它退缩了。Vector
VectorMap
Vector
VectorMap
此继承还会导致其他问题情况。例如,考虑制作 .看看 base 的复制构造函数是做什么的。它为副本分配内存。但是副本的 desturctor 将指针设置为 null,因此在这种情况下,指针被删除零次。它会泄漏内存。VectorMap
VectorMap
打个比方,禁用切片将是伤口的绷带,但你真正应该做的是不要把手伸进正在运行的搅拌机里。如果应该没有所有权,那么它不应该继承一个拥有所有权的基础。我甚至不清楚上课的意义是什么。VectorMap
VectorMap
此外,对资源具有唯一所有权的类(如 real)应使用私有访问说明符封装该裸指针。当然,这样的类有时仍然提供了一种复制或丢弃该值的方法(如 和 ),但重要的是,它只能通过特定函数发生,以减少意外违反所有权语义的机会。Vector
std::vector::data
std::unique_ptr::release
另一个严重的错误:
_ptr=new int[v3._size];
// ...
delete _ptr;
不能是指向动态数组的指针。您必须使用 .使用会导致未定义的行为。delete
delete[]
delete
另一个错误:您忘记包含声明 .另外,我建议改用。memcpy
std::copy
评论
VectorMap
Vector
std::span
评论
~Vector(void)
~VectorMap(void)
void
move constructor
VectorMap