C++11 如何在C+中设计数组型智能指针+;11

C++11 如何在C+中设计数组型智能指针+;11,c++11,smart-pointers,C++11,Smart Pointers,这是一个包含图像数据的类 class MyMat { public: int width, height, format; uint8_t *data; } 我想设计具有自动内存管理功能的MyMat。图像数据可以在多个对象之间共享。 我将要设计的常见API: “C++”11+< +)分配:共享数据 MyMat a2(w, h, fmt); ................. a2 = a1; +)访问数据应该简单而简短。 可以直接使用原始指针 一般来说,我想将MyMat设计


这是一个包含图像数据的类

class MyMat
{
public:
    int width, height, format;
    uint8_t *data;
}
我想设计具有自动内存管理功能的MyMat。图像数据可以在多个对象之间共享。 我将要设计的常见API:

“C++”11+< +)分配:共享数据

MyMat a2(w, h, fmt);
.................
a2 = a1; 
+)访问数据应该简单而简短。 可以直接使用原始指针

一般来说,我想将MyMat设计成OpenCV::Mat

你能给我推荐一个合适的设计吗

1)使用std::矢量数据
我必须编写一些代码来删除复制构造函数和赋值运算符,因为有人可以调用它们并导致内存复制。
编译器必须支持复制省略和返回值优化。
总是使用移动分配和按引用传递是不方便的

a2 = std::move(a1)
void test(MyMat &mat)
std::queue<MyMat> lists;
lists.push_back(std::move(a1))
..............................

std::array
-固定长度就地缓冲区(美化数组)
std::vector
-可变长度缓冲区
std::共享\u ptr
-共享所有权数据
std::weak_ptr
-共享数据视图过期
std::unique\u ptr
-唯一所有权
std::string\u视图,std::span,std::ref,&,*
-对数据的引用,无所有权假设

最简单的设计是有一个单一的拥有者,RAII强制使用生命时间,确保在特定时间需要生存的所有东西都是活的,不需要其他所有权,所以一般来说,在进一步复杂化之前,我会看看自己是否能活下去(除非我可以将所有数据放在堆栈上,否则我甚至不需要
唯一的\u ptr


另一方面-共享指针不是空闲的,它们需要为共享状态动态分配内存(如果分配不正确,则需要两次分配:),而唯一指针则是真正的“零”开销RAII。

std::array
-固定长度就地缓冲区(美化数组)
std::vector
-可变长度缓冲区
std::共享\u ptr
-共享所有权数据
std::weak_ptr
-共享数据视图过期
std::unique\u ptr
-唯一所有权
std::string\u视图,std::span,std::ref,&,*
-对数据的引用,无所有权假设

最简单的设计是有一个单一的拥有者,RAII强制使用生命时间,确保在特定时间需要生存的所有东西都是活的,不需要其他所有权,所以一般来说,在进一步复杂化之前,我会看看自己是否能活下去(除非我可以将所有数据放在堆栈上,否则我甚至不需要
唯一的\u ptr


另一方面,共享指针不是空闲的,它们需要为共享状态动态分配内存(如果分配不正确,则需要两次分配:),而唯一指针是真正的“零”开销RAII。

通常期望矩阵类是具有深度复制的值类型。因此,请坚持使用
std::vector
,让用户决定在其特定环境中复制是否昂贵



代替数组的原始指针,更喜欢
std::unique\u ptr
(注意方括号)

通常期望矩阵类是具有深度复制的值类型。因此,请坚持使用
std::vector
,让用户决定在其特定环境中复制是否昂贵



代替数组的原始指针,更喜欢
std::unique\u ptr
(注意方括号)

矩阵应该使用值语义,它们应该几乎可以自由移动

矩阵也应该支持视图类型

对于基本矩阵,有两种方法是有意义的

首先,一种矩阵类型,它将
向量
包装为
跨步
字段。与手动滚动的指针相比,它的开销是3,而不是2个指针(或1个指针和一个大小)。我认为这并不重要;调试
向量
等的简易性使其更值得这样做

在这种情况下,您需要编写一个单独的矩阵视图

我将使用CRTP为实现
operator[]
和stride字段创建一个公共基类


一种独特的基本矩阵方法是使矩阵不可变。在这种情况下,矩阵包装一个
std::shared_ptr
和一个
std::shared_ptr
和(本地,或与互斥体一起存储)宽度、高度和步幅字段

复制这样的矩阵只会复制句柄

修改这样的矩阵会导致您获取
std::mutex
,然后检查
shared\u ptr
是否具有
use\u count()==1
。如果是,则丢弃const并修改
共享\u ptr
中引用的数据。如果没有,则复制缓冲区,创建新的互斥体,并在新状态下操作

这是一个写时拷贝矩阵缓冲区:

template<class T>
struct cow_buffer {
  std::size_t rows() const { return m_rows; }
  std::size_t cols() const { return m_cols; }

  cow_buffer( T const* in, std::size_t rows, std::size_t cols, std::size_t stride ) {
    copy_in( in, rows, cols, stride );
  }

  void copy_in( T const* in, std::size_t rows, std::size_t cols, std::size_t stride ) {
    // note it  isn't *really* const, this matters:
    auto new_data = std::make_shared<T[]>( rows*cols );
    for (std::size_t i = 0; i < rows; ++i )
      std::copy( in+i*stride, in+i*m_stride+m_cols, new_data.get()+i*m_cols );
    m_data = new_data;
    m_rows = rows;
    m_cols = cols;
    m_stride = cols;
    m_lock = std::make_shared<std::mutex>();
  }

  template<class F>
  decltype(auto) read( F&& f ) const {
    return std::forward<F>(f)( m_data.get() );
  }
  template<class F>
  decltype(auto) modify( F&& f ) {
    auto lock = std::unique_lock<std::mutex>(*m_lock);
    if (m_data.use_count()==1) {
      return std::forward<F>(f)( const_cast<T*>(m_data.get()) );
    }
    auto old_data = m_data;
    copy_in( old_data.get(), m_rows, m_cols, m_stride );
    return std::forward<F>(f)( const_cast<T*>(m_data.get()) );
  }
  explicit operator bool() const { return m_data && m_lock; }
private:
  std::shared_ptr<T> m_data;
  std::shared_ptr<std::mutex> m_lock;
  std::size_t m_rows = 0, m_cols = 0, m_stride = 0;
};
模板
结构缓冲区{
std::size_t rows()常量{返回m_rows;}
std::size\u t cols()常量{return m\u cols;}
母牛缓冲区(常数*英寸,标准::大小行,标准::大小列,标准::大小跨步){
以(英寸、行、列、步幅)复制;
}
无效副本输入(常量输入,标准::大小行,标准::大小列,标准::大小跨步){
//注意,它不是*真的*常数,这很重要:
自动新建_数据=标准::使_共享(行*列);
对于(std::size\u t i=0;itemplate<class T>
struct cow_buffer {
  std::size_t rows() const { return m_rows; }
  std::size_t cols() const { return m_cols; }

  cow_buffer( T const* in, std::size_t rows, std::size_t cols, std::size_t stride ) {
    copy_in( in, rows, cols, stride );
  }

  void copy_in( T const* in, std::size_t rows, std::size_t cols, std::size_t stride ) {
    // note it  isn't *really* const, this matters:
    auto new_data = std::make_shared<T[]>( rows*cols );
    for (std::size_t i = 0; i < rows; ++i )
      std::copy( in+i*stride, in+i*m_stride+m_cols, new_data.get()+i*m_cols );
    m_data = new_data;
    m_rows = rows;
    m_cols = cols;
    m_stride = cols;
    m_lock = std::make_shared<std::mutex>();
  }

  template<class F>
  decltype(auto) read( F&& f ) const {
    return std::forward<F>(f)( m_data.get() );
  }
  template<class F>
  decltype(auto) modify( F&& f ) {
    auto lock = std::unique_lock<std::mutex>(*m_lock);
    if (m_data.use_count()==1) {
      return std::forward<F>(f)( const_cast<T*>(m_data.get()) );
    }
    auto old_data = m_data;
    copy_in( old_data.get(), m_rows, m_cols, m_stride );
    return std::forward<F>(f)( const_cast<T*>(m_data.get()) );
  }
  explicit operator bool() const { return m_data && m_lock; }
private:
  std::shared_ptr<T> m_data;
  std::shared_ptr<std::mutex> m_lock;
  std::size_t m_rows = 0, m_cols = 0, m_stride = 0;
};