Как вернуть копию вектора, доступную только для чтения - PullRequest
20 голосов
/ 17 марта 2010

У меня есть класс с закрытым атрибутом vector rectVec;

class A {
private:
   vector<Rect> rectVec;
};

У меня вопрос, как я могу вернуть копию моего вектора, доступную только для чтения? Я думаю сделать это:

class A {
public:
  const vect<Rect>& getRectVec() { return rectVect; }
}

Это правильный путь? Я думаю, что это может защитить от вызываемого абонента изменения вектора (добавить / удалить Rect в векторе), а как насчет Rect внутри вектора?

Ответы [ 7 ]

28 голосов
/ 17 марта 2010

Это правильный путь, хотя вы, вероятно, захотите также включить функцию const.

class A {
public:
  const vect<Rect>& getRectVec() const { return rectVect; }                           
};

Это позволяет людям вызывать getRectVec, используя const A объект.

6 голосов
/ 17 марта 2010

Это нормальный способ. const означает «Вы не можете изменить это». Это также относится к элементам в контейнере.

Простой тест:

#include <vector>

typedef std::vector<int> int_vec;

struct foo
{
    const int_vec& get(void)
    {
        return v;
    }

    int_vec v;
};

int main(void)
{
    foo f;
    f.v.push_back(1);
    f.v.push_back(2);
    f.v.push_back(3);

    f.get()[0] = 2; // nope
}

const_cast можно использовать для удаления const, но в результате вы получите неопределенное поведение, если измените переменную через него:

int_vec& v = const_cast<int_vec&>(f.get()); // this is okay
v[0] = 0; // but now we've entered undefined behavior
2 голосов
/ 18 марта 2010

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

2 голосов
/ 17 марта 2010

Это правильный путь, если пользователь не отбрасывает константу, используя const_cast.

1 голос
/ 14 октября 2015

Я знаю, что это довольно старый пост, но это один из лучших результатов Google при поиске "c ++ read only vector". Вот почему я все же хочу опубликовать свой подход.

Если вы хотите, чтобы сам контейнер был константным, но не его элементами, вы можете использовать подход, подобный этому:

template<class Container>
class Enumerable
{
public:
    Enumerable(Container& container) : _container(container) {}

    auto begin() const { return _container.begin(); }
    auto end() const { return _container.end(); }

    const Container& GetContainer() const { return _container; }
    const Container* operator->() const { return &_container; }

private:
    Container& _container;
};

С этим вы можете перебирать свой контейнер и изменять его элементы, сохраняя при этом тот же контейнер. Вы можете захотеть предоставить больше функциональных возможностей контейнера, специализируя класс, например, для векторы, предоставляя оператор индексации.

Я не совсем уверен, что это хороший дизайн для показа такого контейнера, но это определенно полезный шаблон для некоторых сценариев.

1 голос
/ 18 марта 2010

Как насчет того, чтобы вместо возврата ссылки на ваш вектор возвращать новый тип, который переносит вектор (содержит константную ссылку на вектор) и предоставляет только те функции, которые вы хотите разрешить вызывающей стороне. Я предполагаю, что это немного, потому что вы хотите предотвратить изменчивость вектора.

0 голосов
/ 17 марта 2010

Таким образом, использование «const &» должно указывать любому программисту на C ++: вы действительно не должны изменять это. Если вы действительно параноик, вам придется клонировать вектор.

...