假设我正在开发一个小型电影数据库。在像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行包含一个Abstract Factory,它返回某个基类的子类,因此这里需要返回一个指针。问题是,应该返回什么样的指针? std::unique_ptr
似乎很合适。
在第2行构造MovieModel
,它将数据库连接作为参数并存储以供将来使用。由于一个连接可以在一个或多个模型之间共享,因此数据库连接应该传递并存储为std::shared_ptr
,我猜想。但是,我应该将std::unique_ptr
创建的ConnectionFactory
转换为shared_ptr
还是修改ConnectionFactory
以返回shared_ptr
?
在第3行中,一个对象存储在数据库中。由于Movie
很简单"数据" class,它应该通过const引用传递值,或者更好。这很简单,但在第4行检索另一个对象。由于Movie
具有"值"语义,按值返回似乎很自然。但是当找不到特定的电影时会发生什么?抛出异常或将返回类型更改为智能指针并在这种情况下返回nullptr
是否更好?
最后,返回一组对象。返回容器(例如std::vector
)对象或(智能)指针容器是否更好?在后一种情况下,哪些指针?
答案 0 :(得分:3)
案例1 + 2:我认为最初由shared_ptr
返回是有意义的,因为数据库连接本身似乎是“可共享的”#34;在这个设计中。这样,Case2解决了问题。
案例3:通过const引用传递Movie
。如果Movie
是一个类似值的类(并且没有任何昂贵的复制句柄),那么带有const-ref参数的简单单个版本的store
应该可以并保持代码简单。
如果您需要建模"未找到"在fetch
方法中,使用boost::optional<Movie>
(或类似的东西)作为返回值。
案例最后:对于Movie
,使用按值排序的集合(std::vector<Movie>
)。 (在C ++ 11中,无论如何都会移动返回的向量。)
答案 1 :(得分:2)
db = ConnectionFactory.get_connection(db_name)#(1)创建数据库 连接
谁拥有db?当它被摧毁?
std::unique_ptr
std::unique_ptr
并将原始指针传递给其他对象std::shared_ptr
请注意,在上述所有情况下,工厂应返回unique_ptr
,除非它返回现有的共享连接,如果是shared_ptr
。 unique_ptr
可以自动升级到shared_ptr
model = MovieModel(db)#(2) 对象 - 关系映射器
std::move(db)
db.get()
star_wars = Movie("Star Wars", ...) model.store(star_wars) # (3) Save object
两个选项:
const Movie&
和Movie&&
如果您不想在此功能中再次使用star_wars,请致电std::move(star_wars)
et = model.fetch(&#34; E.T。&#34;)#(4)检索一个 对象
作为异常或optional<Movie>
movies = model.fetch_all()#(5)全部检索 对象
std::vector<Movie>
答案 2 :(得分:1)
编辑:我在这里说了一些不那么聪明的东西,完全忽略了标题中的C ++ 11。
关于3和5的一些个人观点:
3)我想不出有什么理由在这里使用value而不是const引用。至少只要存储不会以某种非常不寻常的方式发生。
最后一点:我总是更喜欢指针容器,以最大限度地减少内存周围的随机复制。在C ++ 11中,您可以使用unique_ptr或shared_ptr,具体取决于它们以后的用途。