如何从派生类中禁用移动构建基类?

发布于 2025-01-23 11:21:48 字数 1723 浏览 0 评论 0原文

在以下代码中,我想从派生类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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

想挽留 2025-01-30 11:21:48

主要问题是泥泞的所有权语义。

vector创建一个资源(动态数组),显然旨在对其拥有独特的所有权。

vectormap另一方面,将指针在其构造函数中取指针,并将其授予其基本vector获得所有权。但是,就在破坏之前,vectormap通过设置基本vector指针将所有权撤销。因此,vectormap假装拥有资源为止,直到该为此重新降低所有权的责任为止。

这种继承也导致其他问题情况。例如,考虑制作vectormap的副本。查看基础复制构造函数的作用。它为复制品分配内存。但是vectormap副本的命令器将指针设置为null,因此在这种情况下,指针被删除零次。它泄漏了内存。

就像一个类比一样,禁用切片是伤口的绷带,但您真正应该做的就是不要将手伸入跑步的搅拌机中。如果VectorMap应该没有所有权,则它不应继承获得所有权的基础。我还不清楚vectormap类的意义是什么。

此外,具有对资源(例如vector)的独特所有权的类,确实应该将其用私人访问说明符封装。当然,此类类有时仍然提供一种复制或丢弃该值的方法(例如std :: vector :: data and std :: simolor_ptr :: repartion_ptr :: Release),但是重要的是,只有通过特定功能才能减少意外违反所有权语义的机会。


另一个严重的错误:

_ptr=new int[v3._size];
// ...
delete _ptr;

您不能删除一个指向动态数组的指针。您必须使用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 base Vector that takes ownership. But right before destruction, VectorMap rescinds the ownership by setting the base Vector 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 the VectorMap 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 of VectorMap 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 (like std::vector::data and std::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:

_ptr=new int[v3._size];
// ...
delete _ptr;

You must not delete a pointer to a dynamic array. You must use delete[]. Using delete results in undefined behaviour.


Another bug: You forgot to include the header that declares memcpy. Also, I would recommend using std::copy instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文