C++ C++;11智能指针用例

C++ C++;11智能指针用例,c++,c++11,smart-pointers,C++,C++11,Smart Pointers,假设我正在开发一个小型电影数据库。用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_w

假设我正在开发一个小型电影数据库。用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\u ptr
转换为
shared\u ptr
还是修改
ConnectionFactory
以返回
shared\u ptr

在第3行中,存储在数据库中的对象。由于
Movie
是一个简单的“数据”类,所以应该通过值传递,或者更好地通过常量引用传递。这很简单,但在第4行中检索到另一个对象。由于
Movie
具有“值”语义,按值返回似乎很自然。但当找不到特定的电影时会发生什么呢?在这种情况下,是抛出异常,还是将返回类型更改为智能指针并返回
nullptr


最后,返回一个对象集合。返回对象的容器(例如,
std::vector
)或(智能)指针的容器更好吗。在后一种情况下,哪些指针?

情况1+2:我认为通过
shared\u ptr
最初返回是有意义的,因为在这种设计中,DB连接似乎本质上是“可共享的”。这样,案例2就能自行解决

案例3:通过常量引用传递
电影
。如果
Movie
是一个类似值的类(并且没有任何昂贵的复制句柄之类的东西),那么带有const ref参数的
store
的简单单一版本应该可以做到这一点,并保持代码简单

如果需要在
fetch
方法中对“notfound”建模,请使用
boost::optional
(或类似内容)作为返回值


最后一个案例:对于
电影
使用值集合(
std::vector
)。(在C++11中,返回的向量将被移动。)

编辑:我在这里说了一些不太聪明的事情,完全忽略了标题中的C++11

关于第3条和第5条的一些个人意见:

3) 我想不出任何理由在这里使用value来代替const引用。至少只要存储不是以某种非常不寻常的方式发生

最后一点:我总是希望有一个指针容器来最小化随机复制内存。在C++11中,您可能可以在它们中使用unique_ptr或shared_ptr,这取决于它们以后的用途

db=ConnectionFactory.get_连接(db_名称)#(1)创建数据库 联系

谁拥有db?什么时候被摧毁

  • 这个堆栈拥有它,应该在最后销毁=>use
    std::unique\u ptr
  • 这将保存在类(例如MovieManager)成员中,并且该类将在所有其他对象=>使用
    std::unique_ptr
    并将原始指针传递给其他对象时继续存在
  • db可能比该堆栈和类更长寿,并与其他对象共享=>
    std::shared\u ptr
  • 注意:在上述所有情况下,factory应该只返回一个
    唯一的\u ptr
    ,除非它返回一个现有的共享连接,这种情况下它是一个
    共享的\u ptr
    <代码>唯一\u ptr可以自动升级到
    共享\u ptr

    模型=电影模型(db)#(2) 对象到关系映射器

  • 如果db是std::unique\u ptr,并且您希望MoviewModel从现在起拥有所有权,
    std::move(db)
  • 模型将在此堆栈中销毁,传递
    db.get()
  • 模型需要共享所有权,因为任何一个模型都可能最后被销毁,并作为共享\u ptr传递
  • 两种选择:

  • const-Movie&
    Movie&
  • 让商店按价值拍摄电影
  • 如果您不想在此函数中再次使用星球大战,请调用
    std::move(星球大战)

    et=model.fetch(“E.T.”)(4)检索一个 反对

    作为异常对象或
    可选

    movies=model.fetch#all()#(5)检索所有 物体


    std::vector

    我建议您不要将智能指针视为指针,而是将其视为所有权:您用于一次只能有一个所有者的对象,而您可以用于可以有多个并发所有者的对象。因此,如果一个对象可能有多个所有者,我应该使用
    shared\u ptr
    ?是的,这是个好主意。@el.pescado或者,看看你是否可以安排你的代码,使对象有一个所有者和多个用户(所有者比所有其他用户都活得长)。然后您可以使用
    unique\u ptr
    ,它更简单,更容易推理。共享所有权不应该是唯一的选择default@jalf我认为,共享所有权比人为地创建比所有用户寿命更长的所有者要简单得多。只有在代码中自然发生这种情况时,我才会考虑这种方法。但是在一个许多不同的阶层并行地做许多不同的事情的环境中,仅仅分享所有权而不是试图猜测谁活得最长似乎更简单,也不容易出错。我同意这些答案。虽然我可能需要
    fetch\u all
    获取一个输出迭代器,而不是返回任何内容。
    star_wars = Movie("Star Wars", ...) 
    model.store(star_wars)    # (3) Save object