Как вернуть "только для чтения" копию вектора

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

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

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

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

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

Ответы

Ответ 1

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

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

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

Ответ 2

Это нормальный путь. 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, но в итоге вы получите поведение undefined, если вы измените переменную через него:

int_vec& v = const_cast<int_vec&>(f.get()); // this is okay
v[0] = 0; // but now we've entered undefined behavior

Ответ 3

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

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;
};

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

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

Ответ 7

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