Как правильно вернуть большой вектор - PullRequest
5 голосов
/ 23 июня 2011
   vector<Foo*>&         getVectorOfFoo();

Я хочу предоставить список моих объектов Foo другим. Это лучший способ сделать это? Я возвращаю ссылку здесь и не копирую правильно?

Вызывающий абонент может (случайно) изменить этот список, верно? Есть ли способ избежать этой возможности? Могу ли я вернуть константный вектор? Но они всегда могут модифицировать объекты Foo, и я мало что могу сделать там. 10-20 разных людей будут писать код, который использует этот список Foo.

Ответы [ 4 ]

9 голосов
/ 23 июня 2011

Первый не возвращает список указателей.
Это делает его вдвойне неясным относительно разрешенных действий.

У Boost есть решение (как обычно).
Вернуть указатель контейнера.Это выставляет указатели как обычные элементы.

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();
}
1 голос
/ 23 июня 2011

Включение возвращаемого типа контейнера в сигнатуру метода в значительной степени помешает вам когда-либо изменить базовый тип контейнера, если альтернативный контейнер станет более подходящим в будущем.

Вы должны хотя бы рассмотреть возможность использования typedef, чтобы скрыть фактический тип контейнера, и документировать минимальные возможности возвращаемого объекта, а не возвращать vector напрямую.

Но вы можете вместо этого предоставить интерфейс итератора, например, YourThing::const_iterator getFooBegin() и getFooEnd(). Таким образом, клиентский код не может изменять базовые объекты контейнера OR, и на самом деле ему даже не нужно знать тип контейнера, что обеспечивает большую гибкость в будущем.

Если вы предпочитаете возвращать контейнер, вам нужно точно решить, что такое семантика, исходя из вопроса, который звучит так, будто вы хотите, чтобы он был только для чтения. В этом случае вам, скорее всего, придется сделать копию контейнера в другой vector, который будет содержать константные указатели вместо неконстантных, поэтому клиент не сможет их изменить. Альтернативно, другой ответ дал действительно хорошее предложение использовать контейнеры с указателями наддува.

1 голос
/ 23 июня 2011

Как уже было сказано, предоставьте постоянный доступ к контейнеру.

Но это все еще не "идеально", потому что вам нужно представить контейнер всему миру, поэтому, если вы измените его, вы заставите пользовательский код измениться, если интерфейс больше не тот.

Но есть последняя надежда:

Если вы можете использовать лямбда-выражения (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 голос
/ 23 июня 2011

верните его как const.

const vector<Foo *> &getVectorOfFoo();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...