приведите stl :: vector, содержащий указатели на stl :: vector, содержащий константные указатели - PullRequest
2 голосов
/ 14 сентября 2011

Рассмотрим следующий класс:

class SomeInfo
{
private:
    std::vector<someObj *> _myVector;

public:
    const std::vector<const someObj*>& getInfoVector() const
    {
        return _myVector;
    }
};

Когда я пытаюсь скомпилировать с помощью gcc 4.1.2, выдается следующая ошибка:

error: invalid initialization of reference of type 
‘const std::vector<const someObj*, std::allocator<const someObj*> >&’ 
from expression of type 
‘const std::vector<someObj*, std::allocator<someObj*> >

Если я удаляю 'const'перед' someObj * ', затем он компилируется, но я не хочу возвращать вектор с неконстантными указателями, потому что я не хочу, чтобы объекты, на которые они ссылаются, изменялись извне моего класса SomeInfo.Что бы вы сделали в этой ситуации?

Ответы [ 4 ]

3 голосов
/ 14 сентября 2011

В этой ситуации я хотел бы забыть о возвращении vector (или ссылки на него). Вызывающий не может вносить какие-либо изменения, поэтому ему не нужно видеть какой-либо конкретный контейнер. Другие ответы объясняют, почему вы не можете ссылаться на свой вектор, как если бы он был вектором const someObj*. В этом отношении, если в будущем вы измените свой класс на deque вместо vector, вы не сможете вернуть ссылку на него, как если бы это был вектор. Поскольку вызывающим просто необходим доступ к элементам, давайте дадим им следующее:

const someObj *getInfoAt(size_t n) const {
    return _myVector.at(n);
}

const_info_iterator getInfoBegin() const {
    return _myVector.begin();
}

const_info_iterator getInfoEnd() const {
    return _myVector.end();
}

size_t getInfoSize() const {
    return _myVector.size();
}

// plus anything else they need.

const_info_iterator - это typedef для класса, который немного раздражает при написании. Он должен обернуть std::vector<someObj *>::const_iterator и соответствовать типу operator*. boost::transform_iterator может быть полезно, или это не так уж плохо писать с нуля. Однако двунаправленные итераторы требуют большинства перегрузок операторов.

Теперь, если вызывающий действительно хочет вектор const someObj*, то с помощью моего интерфейса они могут легко получить снимок в любой конкретный момент:

std::vector<const someObj*> mycopy(myinfo.getInfoBegin(), myinfo.getInfoEnd());

Чего они не могут иметь, так это vector, который постоянно отражает изменения, сделанные в каком-то другом vector другого типа где-то еще - std::vector просто не делает этого.

0 голосов
/ 14 сентября 2011

вы можете написать getInfoVector так:

std::vector<const someObj*> getInfoVector() const
{
  std::vector<const someObj*> obj;
  std::copy( _myVector.begin(), _myVector.end(), std::back_inserter( obj ) );
  return obj;
}
0 голосов
/ 14 сентября 2011

Что бы вы сделали в этой ситуации?

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

const someObj* SomeInfo::getSomeObjAt(const size_t& idx) const {
  return this->_myVector.at(idx);
}

еще лучше во многих контекстах, просто заставьте SomeInfo не раскрыть свои внутренние данные.

0 голосов
/ 14 сентября 2011

std::vector<T*> и std::vector<const T*> не одного типа. Как вы можете написать это:

std::vector<T*> obj(100);
std::vector<const T*> & ref = obj; //error

Это то, что вы делаете в своем коде, что недопустимо. Вы можете сделать ссылку одного типа, чтобы ссылаться на объект другого типа.

Так попробуйте это:

std::vector<const someObj*> getInfoVector() const
{
    return std::vector<const someObj*>(_myVector.begin(), _myVector.end());
}

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

...