繁体   English   中英

如何使 class 可以被其他类移动?

[英]How to make a class movable by other classes?

假设我有一个 RAII class,如vector

class vector{
   double* data_;
   int size_;
public:
   explicit vector(int size = 0) : data_{new double[size]}, size_{size}{}
   vector(vector const& other) : data_{new double[other.size_]}, size_{other.size_}{}
   int size() const{return size_;}
   double const* data() const{return data_;}
   double* data(){return data_;} // optional but common
   ~vector(){if(size_) delete[] double;}
}

如果我想让 class 可移动,我可以添加一个移动构造函数。

   vector(vector&& other) : size_{other.size_}, data_{other.data_}{other.size_ = 0;}

到目前为止,模数错别字和迂腐评论,仅此而已。

但是,我想让 class 可以由与我的vector无关的其他类移动。 我知道这基本上需要类似于移动构造函数的代码,但在独立的 class 中。

class SuperVector{
   double* data_begin_;
   double* data_end_; // I don't use size to show having two independent implementations
   std::string super = "super";
   SuperVector(vector&& v) ... {...} // what here? what needs to change in `vector`?
};

我几乎可以肯定,无论SuperVector代码如何, vector都需要以某种方式进行更改以允许这样做。

问题是是否有一种常用的协议来允许来自不相关的 class 的这些可移动性。 或者这是尚未考虑的事情。 (我想有时人们想从std::vector转移到一个不相关的类)。


前期工作:

我能想象的解决方案是:

  1. 使SuperVector成为vector朋友,然后简单地实现“进入”移动

     SuperVector(vector&& v): data_begin_{v.data()}, data_end_{v.data() + v.size()}{v.size_ = 0;}

    这样做的问题是友谊增加了很多耦合,它不是一个通用的解决方案。

  2. 给予对向量内部表示的更多访问权(特别是使其可分配)。

     int& vector::size(){return size_;}
     SuperVector(vector&& v): data_begin_{v.data()}, data_end_{v.data() + v.size()}{v.size() = 0;}

    这真的很糟糕,因为任何人都可以改变size ,打破不变量等。

    现在是更复杂和重要的选择。

  3. 像 2) 但添加特殊功能:

     class vector{... [[nodiscard]] // false sense of security double* moved_data()&&{ // for lack of a better name (simply data()&&?) size_ = 0; return data_; }...}

    并将其用作

     SuperVector(vector&& v){ // or some variation of this data_end_ = v.data() + v.size()}; data_begin_ = std::move(v).moved_data(); }

    这样做的缺点是需要修改vector ,这是意料之中的。 而且任何人都可以调用moved_data并使vector无效似乎很危险。 此外,这取决于[[nodiscard]]并且可以从不相关的类中产生 memory 泄漏。 最糟糕的vector似乎是“过早地”从 state 移动,远在 object 真正从(客户端)其他 class 移动之前。

    最后,

  4. 也许我缺少的是某种新的智能指针,它会将移动延迟到以后的时间。 我在这里move_ptr

     template<class CustomMover> class move_ptr{ // or transfer_ptr double* ptr_; CustomMover mover_; public: move_ptr(double* ptr, CustomMover mover): ptr_{ptr}, mover_{std::move(mover)}{} // probably movable too. [[nodiscard]] operator double*(){ // protect against twice move if(ptr_) mover_(); auto ret = ptr_; ptr_ = nullptr; return ret; } // ~move_ptr(){} // if nobody took care, that is ok, nothing happens. }
     class vector{... auto moved_data()&&{ // for lack of a better name (or simply data()&&?) auto custom_mover = [&size_]{size_ = 0;}; return move_ptr<decltype(custom_mover)>{data_, custom_mover_}; }...}

    (其他可能的名称是move()&mdata()&mdata()&&data()&& 。)

    请注意,移动的副作用是由智能指针携带的。

    并将其用作

     SuperVector(vector&& v){ // or some variation of this data_end_ = v.data() + v.size()}; data_begin_ = std::move(v).moved_data(); // this will set size to zero }

    我确信有一些边缘情况我没有考虑这个简单的代码,但我希望主要思想是清楚的。

    欢迎修复。

    这个智能指针是否有意义,或者是否已经在某处实现了类似“移动管理器指针”的东西?

    我看到这类似于std::unique_ptr ,除了移动是由复制的智能指针实现的,而且自定义操作仅在分配时发生(到常规指针)。

    使用std::unique_ptr也许可以达到相同的效果,但我不知道如何。

这是对这个更抽象问题的具体应用: 右值引用和指针之间的确切对应关系?

您已经了解了所有可能性,您的问题的直接答案是不存在通用协议。

这个答案回顾了 std::lib 中允许将所有权转移到不相关类型的几个地方。

unique_ptr

auto p = up.release();

unique_ptr up已放弃其资源的所有权,现在由客户端负责。

unique_lock

auto m = ul.release();

unique_lock ul已放弃对其互斥锁的锁定 state 的所有权,现在由客户端负责。

关联容器和无序容器

extract成员 function 查找单个元素(通过键或迭代器)并在名为container::node_type的类似智能指针的 object 中释放单个节点的所有权。 这个“智能指针”有一个分配器的副本,因此它知道如何自毁。 它还为客户端提供对包含元素的非常量访问。 当元素的关键部分归容器所有时,只有 const 访问可用。

根本不可能有一个通用的解决方案。 从根本上移出一个值意味着您需要了解该值类型的实现细节,特别是它如何管理 memory。

因此,您需要以一种或另一种方式(通过友谊,或者更公开的接口)发布这些实现细节,这通常是不可取的。 无论哪种方式,您都会在类型之间获得紧密耦合,而这根本无法避免。

我也不认为,即使可能,这会像你想象的那样普遍有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM