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;
};