如何从派生类中禁用移动构建基类?
在以下代码中,我想从派生类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);
}
如您所见,如果在行vector v2 = vectormap(v1._ptr,5);
中调用move构造函数,则v1 v1
中的数据指针将被删除两次,一个是v2
,另一个是v1
。由于他们共享相同的指针。有什么方法可以修改vectormap
在这种情况下调用复制构造函数而不是移动构造函数?
In the following code, I want to disable the move construction of base class Vector
from derived class VectorMap
, and call the copy constructor.
#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);
}
As you can see, if move constructor is called in the line Vector v2=VectorMap(v1._ptr,5);
, the data pointer in v1
will be deleted twice, one is by v2
, and another is by v1
. Since they share the same pointer. Is there any way to modify VectorMap
to call copy constructor rather than move constructor in such case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
主要问题是泥泞的所有权语义。
vector
创建一个资源(动态数组),显然旨在对其拥有独特的所有权。vectormap
另一方面,将指针在其构造函数中取指针,并将其授予其基本vector
获得所有权。但是,就在破坏之前,vectormap
通过设置基本vector
指针将所有权撤销。因此,vectormap
假装拥有资源为止,直到该为此重新降低所有权的责任为止。这种继承也导致其他问题情况。例如,考虑制作
vectormap
的副本。查看基础复制构造函数的作用。它为复制品分配内存。但是vectormap
副本的命令器将指针设置为null,因此在这种情况下,指针被删除零次。它泄漏了内存。就像一个类比一样,禁用切片是伤口的绷带,但您真正应该做的就是不要将手伸入跑步的搅拌机中。如果
VectorMap
应该没有所有权,则它不应继承获得所有权的基础。我还不清楚vectormap
类的意义是什么。此外,具有对资源(例如
vector
)的独特所有权的类,确实应该将其用私人访问说明符封装。当然,此类类有时仍然提供一种复制或丢弃该值的方法(例如std :: vector :: data
andstd :: simolor_ptr :: repartion_ptr :: Release
),但是重要的是,只有通过特定功能才能减少意外违反所有权语义的机会。另一个严重的错误:
您不能
删除
一个指向动态数组的指针。您必须使用delete []
。使用delete
导致未定义的行为。另一个错误:您忘了包括声明
memcpy
的标头。另外,我建议您改用std ::复制
。The primary problem is muddy ownership semantics.
Vector
creates a resource (dynamic array), and is apparently intended to have unique ownership over it.VectorMap
on the other hand takes a pointer in its constructor, and gives it to its baseVector
that takes ownership. But right before destruction,VectorMap
rescinds the ownership by setting the baseVector
pointer to null. So,VectorMap
sort of pretends to own the resource until it's time for the responsibility of the ownership at which point it backs down.This inheritance also causes other problem situations. Consider for example making a copy of
VectorMap
. Look at what the copy constructor of the base does. It allocates memory for the copy. But the desturctor of theVectorMap
copy sets the pointer to null, so in this case the pointer is deleted zero times. It leaks memory.As an analogy, disabling slicing would be a bandage for the wound, but what you really should do is to not stick your hand inside a running blender. If
VectorMap
is supposed to not have ownership, then it shouldn't inherit a base that takes ownership. It's unclear to me what the point ofVectorMap
class even is.Furthermore, a class that has unique ownership of a resource such as
Vector
really should encapsulate that bare pointer with private access specifier. Sure, such classes sometimes still provide a way to copy or throw away that value (likestd::vector::data
andstd::unique_ptr::release
), but it's important that only happens through a specific function to reduce chance of accidental violation of ownership semantics.Another serious bug:
You must not
delete
a pointer to a dynamic array. You must usedelete[]
. Usingdelete
results in undefined behaviour.Another bug: You forgot to include the header that declares
memcpy
. Also, I would recommend usingstd::copy
instead.