我搜索过网络并阅读有关shared_ptr
的Boost文档。 SO上有一个响应,表示写入时写入(COW)的shared_ptr
很糟糕,TR!
已将其从字符串库中删除。关于SO的大多数建议都说使用shared_ptr
而不是常规指针。
该文档还讨论了使用std::unique()
制作COW指针,但我没有找到任何示例。
是否有关于为您执行COW的智能指针或让您的对象使用新的shared_ptr
到克隆对象然后修改克隆对象的讨论?
struct Nutrients;
struct Ingredient
{
Ingredient(const std::string& new_title = std::string(""))
: m_title(new_title)
{ ; }
std::string m_title;
Nutrients ing_nutrients;
};
struct Milk : public Ingredient
: Ingredient("milk")
{ ; }
struct Cream : public Ingredient
: Ingredient("cream")
{ ; }
struct Recipe
{
std::vector< boost::shared_ptr<Ingredient> > m_ingredients;
void append_ingredient(boost::shared_ptr<Ingredient> new_ingredient)
{
m_ingredients.push_back(new_ingredient);
return;
}
void replace_ingredient(const std::string& original_ingredient_title,
boost::shared_ptr<Ingredient> new_ingredient)
{
// Confusion here
}
};
int main(void)
{
// Create an oatmeal recipe that contains milk.
Recipe oatmeal;
boost::shared_ptr<Ingredient> p_milk(new Milk);
oatmeal.add_ingredient(p_milk);
// Create a mashed potatoes recipe that contains milk
Recipe mashed_potatoes;
mashed_potatoes.add_ingredient(p_milk);
// Now replace the Milk in the oatmeal with cream
// This must not affect the mashed_potatoes recipe.
boost::shared_ptr<Ingredient> p_cream(new Cream);
oatmeal.replace(p_milk->m_title, p_cream);
return 0;
}
混淆是如何用奶油替换oatmeal
食谱中的'牛奶'而不影响mashed_potatoes
食谱。
我的算法是:
locate pointer to `Milk` ingredient in the vector.
erase it.
append `Cream` ingredient to vector.
COW指针如何在这里发挥作用?
注意:我在Windows NT,Vista和7上使用MS Visual Studio 2010。
答案 0 :(得分:13)
这里有几个问题捆绑在一起,所以如果我没有按照你期望的顺序解决这些问题,请耐心等待。
关于SO的大多数建议都说使用shared_ptr而不是常规指针。
是和否。不幸的是,许多SO的用户推荐shared_ptr
,好像它是解决所有内存管理相关问题的灵丹妙药。 不是。大多数建议谈论不使用裸指针,这是完全不同的。
真正的建议是使用智能管理器:智能指针(unique_ptr
,scoped_ptr
,shared_ptr
,auto_ptr
),智能容器(ptr_vector
,ptr_map
)或针对难题的自定义解决方案(基于Boost.MultiIndex,使用侵入式计数器等)。
您应该根据需要选择要使用的智能管理器。最值得注意的是,如果您不需要共享对象的所有权,则不应使用shared_ptr
。
什么是COW?
COW(Copy-On-Write)是关于共享数据以“保存”内存并使副本更便宜......而不改变程序的语义。
从用户的角度来看,std::string
是否使用COW并不重要。修改字符串后,所有其他字符串都不受影响。
COW背后的理念是:
它似乎与
shared_ptr
类似,为什么不呢?
它是相似的,但两者都是为了解决不同的问题,因此它们略有不同。
问题在于,由于shared_ptr
无论是否共享所有权都意味着无缝运行,因此COW难以实施“如果唯一所有者”测试。值得注意的是,weak_ptr
的互动使其变得困难。
shared_ptr
,而不是使用weak_ptr
(无论如何它们都对COW没用。)
重要吗?
不,不是真的。事实证明,COW并不是那么棒。大多数时候它是微观优化......并且一次微观悲观化。你可以节省一些内存(虽然只有你不复制大对象才有效),但是你的算法很复杂,这可能会减慢执行速度(你正在引入测试)。
我的建议是不要使用COW。而且不要使用那些shared_ptr
。
个人,我要么:
boost::ptr_vector<Ingredient>
而不是std::vector< boost::shared_ptr<Ingredient> >
(您不需要分享)IngredientFactory
,创建(并管理)成分,并返回Ingredient const&
,Factory
应该比Receipt
更长。 编辑:根据Xeo的评论,似乎最后一项(IngredientFactory
)非常简洁......
对于IngredientFactory
,Receipt
对象将包含std::vector<Ingredient const*>
。注意原始指针:
Receipt
不对内存负责,但可以访问它Receipt
对象使用原始(裸)指针是好的,只要你像对待它一样对待它们。您只需要注意潜在的无效性,并且如果您愿意,您可以重新安装它们 - 并且您相信提供商可以处理生命周期/内存管理方面的问题。
答案 1 :(得分:1)
你无需担心。每个Recipe
对象都有自己的vector
,因此修改它们不会影响另一个,即使它们都碰巧包含指向同一对象的指针。只有当您更改了p_milk
指向的对象的内容时,土豆泥配方才会受到影响,但您没有这样做。您正在修改oatmeal.m_ingredients
对象,该对象与mashed_potatoes.m_ingredients
完全无关。他们是两个完全独立的vector
个实例。