std :: reverse на boost :: ptr_vector разрезает объекты?

Позволять Base а также Derived быть классы с членами данных:

class Base {
public:
Base(int i):f(i)     { }
virtual void print() { cout << "base " << f << endl; }
int f;
};

class Derived: public Base {
public:
Derived(int i):Base(0),g(i) {  }
void print() { cout << "derived " << g << endl; }
int g;
};

Теперь создайте несколько экземпляров Base а также Derived на кучу и хранить их в boost::ptr_vector:

int main(int argc, char *argv[])
{
boost::ptr_vector<Base> v;
v.push_back(new Derived(1));
v.push_back(new Base(2));
v.push_back(new Base(3));
v.push_back(new Derived(4));

распечатать все объекты:

    for (std::size_t i(0); i != v.size(); ++i)
v[i].print();

затем разверните и снова напечатайте:

    std::reverse(v.begin(), v.end());
for (std::size_t i(0); i != v.size(); ++i)
v[i].print();
}

Эта программа печатает:

derived 1
base 2
base 3
derived 4
derived 1
base 3
base 2
derived 4

std::reverse() на boost::ptr_vector звонки std::iter_swap() который в свою очередь вызывает std::swap который меняет элементы, создавая временную копию.

Тем не менее, временная копия нарезает производные объекты. Как видите, int g из Derived объекты 1 и 4 не поменялись местами, так что объекты разбиваются после обмена.

Такое поведение меня озадачивает. не boost::ptr_vector контейнер, чтобы избежать именно такой проблемы?

Что мне нужно здесь, это конструктор виртуальных копий, который не существует в C ++.

Как я могу обойти это? Нужно ли реализовать виртуальную функцию подкачки для Base, так что виртуальная диспетчеризация вызывает другую функцию-член подкачки Derived?

РЕДАКТИРОВАТЬ: зачем копировать объекты в первую очередь? Поскольку вектор хранит только указатели, изменение его должно быть обменом указателей, а не объектов, на которые указывают!
Есть ли функция, которая делает это?

8

Решение

Повышение-х ptr_vector Класс содержит функции-члены, работа которых заключается в манипулировании указателями. Но публичный интерфейс в значительной степени скрывает тот факт, что вектор внутренне хранит указатели. Идея состоит в том, чтобы создать что-то, что ведет себя так, как если бы оно содержало объекты напрямую, но внутренне хранило указатели, чтобы избежать нарезки, когда вы помещаете объект в контейнер. Но если вы скопируете объект из контейнера в объект базового типа, он будет разрезан. Таким образом, вы не должны вызывать такие функции на ptr_vectors.

К сожалению, это означает, что, прежде чем применять какой-либо алгоритм к ptr_vector, вы должны точно понимать, что он делает.

1

Другие решения

Один из возможных способов обойти это использовать

std::reverse(v.base().begin(), v.base().end());

вместо. Он переворачивает указатели вместо самообращающихся итераторов.

0

По вопросам рекламы [email protected]