C++11智能指针用例
C++11 smart pointers use cases
假设我正在开发一个小型电影数据库。在像python这样的动态语言中,我会写:
db = ConnectionFactory.get_connection(db_name) # (1) Create database connection
model = MovieModel(db) # (2) object-to-relational mapper
star_wars = Movie("Star Wars", ...)
model.store(star_wars) # (3) Save object
et = model.fetch("E.T.") # (4) Retrieve one object
movies = model.fetch_all() # (5) Retrieve all objects
当将其转换为C++时,会出现如何传递对象的问题:通过值、通过引用、通过普通的旧指针或通过少数智能指针之一。
第1行包含了一个抽象工厂,它返回某个基类的子类,所以在这里返回指针是必要的。问题是,应该返回什么样的指针?std::unique_ptr
似乎很合适。
在第2行中,构造了MovieModel
,它将数据库连接作为参数并存储它以备将来使用。由于一个连接可以在一个或多个模型之间共享,所以我认为数据库连接应该传递并存储为std::shared_ptr
。但是,我应该将ConnectionFactory
创建的std::unique_ptr
转换为shared_ptr
还是修改ConnectionFactory
以返回shared_ptr
?
在第3行中,一个存储在数据库中的对象。由于Movie
是一个简单的"数据"类,所以它应该通过值传递,或者更好地通过const引用传递。这很简单,但在第4行中检索到了另一个对象。由于Movie
具有"值"语义,按值返回似乎很自然。但当找不到特定的电影时会发生什么呢?在这种情况下,是抛出异常更好,还是将返回类型更改为智能指针并返回nullptr
更好?
最后,返回一个对象集合。返回对象的容器(例如std::vector
)或(智能)指针的容器更好吗。在后一种情况下,哪些指针?
案例1+2:我认为最初由shared_ptr
返回是有意义的,因为在这种设计中,DB连接似乎天生就"可共享"。这样,案例2就能自行解决。
情况3:通过常量引用传递Movie
。如果Movie
是一个类似值的类(并且没有任何昂贵的复制句柄的东西),那么一个简单的带有const-ref参数的store
单一版本应该可以做到这一点,并保持代码简单。
如果您需要在fetch
方法中对"未找到"进行建模,请使用boost::optional<Movie>
(或类似的东西)作为返回值。
Case Last:对于Movie
,按值使用集合(std::vector<Movie>
)。(在C++11中,返回的矢量无论如何都会被移动。)
db=ConnectionFactory.get_connection(db_name)#(1)创建数据库连接
谁拥有数据库?什么时候被摧毁?
- 这个堆栈拥有它,最终应该销毁=>使用
std::unique_ptr
- 这保存在类(例如MovieManager)成员中,只要所有其他对象=>使用
std::unique_ptr
并将原始指针传递给其他对象,该类就会一直存在 - db可能比该堆栈和类更长寿,并与其他对象共享=>
std::shared_ptr
请注意,在上述所有情况下,工厂应该只返回一个unique_ptr
,除非它返回一个现有的共享连接,在这种情况下它是shared_ptr
。unique_ptr
可自动升级为shared_ptr
model=影片model(db)#(2)对象到关系映射器
- 如果db是std::unique_ptr,并且您希望MoviewModel从现在起拥有所有权,则
std::move(db)
- 模型将在此堆栈中销毁,通过
db.get()
- 模型需要共享所有权,因为任何模型都可能最后被销毁,作为shared_ptr传递
star_wars = Movie("Star Wars", ...) model.store(star_wars) # (3) Save object
两种选择:
- 使
const Movie&
和Movie&&
的存储过载 - 使商店按值获取电影
如果您不想在此函数中再次使用star_wars,请调用std::move(star_wars)
et=model.fetch("E.T.")#(4)检索一个目标
作为异常对象或optional<Movie>
movies=model.fetch_all()#(5)检索所有对象
std::vector<Movie>
edit:我在这里说了一些不太聪明的事情,完全忽略了标题中的C++11。
关于3和5的一些个人意见:
3) 我想不出有什么理由在这里使用value而不是const引用。至少只要存储不会以某种非常不寻常的方式发生。
最后一点:我总是喜欢一个指针容器,以尽量减少内存的随机复制。在C++11中,您可能可以在其中使用unique_ptr或shared_ptr,这取决于它们以后的用途。
- 1d 智能指针不适用于语法 (*)++
- 优先顺序:智能指针和类析构函数
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 智能指针作为无序映射键,并通过引用进行比较
- 智能指针概念所有权和寿命
- 正在理解智能指针,但出现错误:未分配正在释放的指针
- 尝试使用智能指针时引发异常
- 我可以制作指向智能指针的智能指针吗?
- 通过智能指针和转换对基本模板参数进行模板推导
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 从堆栈分配的原始指针构造智能指针
- 初始化指向类实例的智能指针并访问其方法
- 如何使用 std::make_shared 创建基类类型的智能指针?
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 编译器不会使用 -std=c++11 编译智能指针
- 具有智能指针的多态性
- C++:矢量分配器行为、内存分配和智能指针
- 通过简单的包装指针C++智能指针性能和差异
- 矢量中的自动指针(智能)
- Std::vector的对象/指针/智能指针传递对象(总线错误:10)