8

Web を検索し、Boost に関するドキュメントを読みましたshared_ptr。SO には、shared_ptrCopy-On-Write (COW) が最悪でTR!、文字列ライブラリから削除されたという応答があります。SOに関するほとんどのアドバイスshared_ptrは、通常のポインターではなく使用するように言っています。

ドキュメントには、COW ポインターを作成するための使用についても記載std::unique()されていますが、例は見つかりませんでした。

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 を使用しています。

4

2 に答える 2

15

ここにはいくつかの質問が 1 つにまとめられているため、予想どおりの順序で回答していない場合でもご容赦ください。

SO に関するほとんどのアドバイスでは、通常のポインターではなく shared_ptr を使用するように指示されています。

はい、いいえ。残念ながら、SO の多くのユーザーは、shared_ptrメモリ管理に関連するすべての問題を解決するための特効薬であるかのように推奨しています。そうではありません。ほとんどのアドバイスは、ネイキッド ポインターを使用しないことについて述べていますが、これは実質的に異なります。

本当のアドバイスは、スマート マネージャーを使用することです: スマート ポインター ( unique_ptrscoped_ptrshared_ptrauto_ptr)、スマート コンテナー ( ptr_vectorptr_map)、または困難な問題に対するカスタム ソリューション (Boost.MultiIndex に基づく、侵入型カウンターの使用など...)。

必要に応じて、使用するスマート マネージャーを選択する必要があります。最も注目すべきは、オブジェクトの所有権を共有する必要がない場合は、shared_ptr.

カウとは?

COW (Copy-On-Write) は、プログラムのセマンティックを変更することなく、データを共有してメモリを「保存」し、コピーを安価にすることです。

ユーザーの観点からは、std::stringCOW を使用するかどうかは問題ではありません。文字列が変更されても、他のすべての文字列は影響を受けません。

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

EDIT : Xeo のコメントに続いて、最後の項目 ( IngredientFactory) は非常に簡潔なようです...

の場合IngredientFactoryReceiptオブジェクトには が含まれますstd::vector<Ingredient const*>。生のポインターに注意してください。

  • Receiptメモリに対する責任はありませんが、メモリへのアクセスは許可されています
  • Receipt指されたオブジェクトがそのオブジェクトよりも長く有効であり続けるという暗黙の保証があります。

参照のように扱う限り、生の (裸の) ポインターを使用してもかまいません。潜在的な無効性に注意する必要があり、必要に応じてそれらを再配置する機能が提供されます-そして、プロバイダーが寿命/メモリ管理の側面を処理することを信頼します.

于 2011-06-06T08:13:40.727 に答える
1

心配することは何もありません。各Recipeオブジェクトには独自のがありますvector。したがって、両方に同じオブジェクトへのポインタが含まれている場合でも、一方を変更しても他方には影響しません。マッシュポテトのレシピは、p_milkポイントするオブジェクトの内容を変更した場合にのみ影響を受けますが、それは行っていません。oatmeal.m_ingredientsとはまったく関係のないオブジェクトを変更していますmashed_potatoes.m_ingredients。それらは2つの完全に独立したvectorインスタンスです。

于 2011-06-05T19:28:40.863 に答える