2011-06-23 6 views
5
vector<Foo*>&   getVectorOfFoo(); 

私のFooオブジェクトのリストを他人に提供したいと思います。これはこれを行う最善の方法ですか?私はここにリファレンスを返して、正しいものをコピーしないのですか?大きなベクトルを正しく返す方法

発信者がこのリストを誤って変更する可能性がありますか?この可能性を避ける方法はありますか? constベクトルを返すことができますか?しかし、彼らはFooオブジェクトをいつも修正することができ、私がそこでできることはあまりありません。 10〜20人の異なる人がFooのこのリストを使用するコードを作成します。

+2

const参照をベクトルに戻すことができます。そうすれば、発信者はそれを変更することはできません。 – Juho

+2

議論から明らかなように、getVectorOfFoo()はクラスのメンバ関数であり、ベクトルはクラスのメンバ変数ですが、これは質問のどこにも記述されておらず、違いがあります。 –

+0

良い議論は、みんなから何かを学んだ。みんなありがとう。 – Mark

答えて

9

まずポインタのリストを返しません。
これは許可された操作について二重に不明瞭にします。

ブーストには(通常通り)解決策があります。
ポインタコンテナを返します。これは、ポインタを通常のメンバとして公開します。

boost::ptr_vector<Foo> const& getVectorOfFoo(); 

ここで、ユーザーは返されたベクトルを変更できません。

例:

#include <boost/ptr_container/ptr_vector.hpp> 

class Foo 
{ 
    public: 
     void plop()   {} 
     void poop() const {} 
}; 

boost::ptr_vector<Foo> const& getVectorOfFoo() 
{ 
    static boost::ptr_vector<Foo> instance; // Create and fill container with FOO objects. 
    instance.push_back(new Foo); 
    return instance; 
} 

int main() 
{ 
    boost::ptr_vector<Foo> const& value = getVectorOfFoo(); 

    value[0].plop(); // Fail. not a const method (comment out this line) 
    value[0].poop(); 
} 
+0

+1、私は前にポインターコンテナのこのアプリケーションについて考えたことはありません。 –

+0

@マークB:私も。これが好きです。 –

1

もconstとして返します。

const vector<Foo *> &getVectorOfFoo(); 
1

既にコンテナへのconstのアクセスを提供する、と述べました。

コンテナを世界に公開する必要があるため、まだ完全ではないため、変更すると、インターフェイスがもはや同じでない場合でもユーザーコードも強制的に変更されます。

しかし、最後の希望があります:

あなたはラムダ(C++ 0xの)を使用することができるなら、あなたはより良いfor_eachアルゴリズムを提供したい:

class MyThingManager 
{ 
public: 

    template< typename FunctorType > // note : could be non-template, in wich case use std::function<> 
    void modify_each_thing(FunctorType f) // if you use std::function, you can put the implementation in the cpp file instead of the header/inline 
    { 
     // do some checks, or maybe generate a list of Things that you allow to modify 

     // then apply the function (here we assume we don't have a separate list - implementation defined for the win!) 
     std::for_each(m_things.begin(), m_things.end(), f); // oh yeah 
     // then we can apply anything more we want 
     check_everything_is_still_valid(); 
     notify_the_world(); 
    } 

    // here is a simpler read-only version 
    template< typename FunctorType > 
    void for_each_thing(FunctorType f) const { std::for_each(m_things.begin(), m_things.end(), f); } 


    // in case you want the user to know how many things to manipulate 
    size_t things_count() const { return m_things;} 



private: 

    std::vector<Thing> m_things; // could be any container, that's isolated from the algorithm! 

}; 

使用法:

MyThingManager manager; 
manager.for_each_thing([](const Thing& thing){ std::cout << "\nA thing : " << thing; }); 
+1

関連:http://en.wikipedia.org/wiki/Visitor_pattern – luke

2

コンテナの戻り値の型をメソッドのシグネチャに組み込むことは、代替コンテナがより適切になった場合に、元のコンテナの型を変更することを防ぐことになります将来は。

実際にコンテナの種類を隠して、vectorを直接返すのではなく、返品オブジェクトの最小機能を文書化するには、少なくともtypedefを使用することを検討してください。

代わりに、YourThing::const_iterator getFooBegin()getFooEnd()のようなイテレータインターフェイスを提供することを検討することもできます。このようにして、クライアントコードは基になるコンテナまたはオブジェクトを変更することはできず、実際にコンテナの種類を知る必要もなく、将来の柔軟性が向上します。

コンテナを返すのが好きな場合は、セマンティクスを読み取り専用にしたいという質問から、セマンティクスを正確に判断する必要があります。その場合は、コンテナのコピーを別のvectorに入れなければなりません。コンテナのコピーは非constではなくconstポインタを含むため、クライアントはそれらを変更できません。代わりに別の答えは、ブーストポインタコンテナを使用するための本当に良い提案を提供しました。

関連する問題