Можно ли создать вектор указателей? - PullRequest
6 голосов
/ 03 мая 2009

Просто интересно, из-за проблемы, с которой я сталкиваюсь, возможно ли создать вектор указателей? И если да, то как? В частности, относительно использования итераторов и .begin () с ним, а именно: Как бы я превратил этот вектор в вектор указателей:

class c
{
     void virtual func();
};

class sc:public c
{
     void func(){cout<<"using func";}
};

sc cobj;

vector<c>cvect
cvect.push_back(cobj);
vector<c>::iterator citer

for(citer=cvect.begin();citer<cvect.end();citer++)
{
     citer->func();
}

Ответы [ 6 ]

17 голосов
/ 03 мая 2009

Конечно.

vector<c*> cvect;
cvect.push_back(new sc);
vector<c*>::iterator citer;
for(citer=cvect.begin(); citer != cvect.end(); citer++) {
  (*citer)->func();
}

Что нужно иметь в виду:

Вам понадобится очистить себя, если вы используете динамически распределенную память, как я делал в моем примере

например:.

 for(...) { delete *i; }

Это можно упростить, используя вектор shared_ptr s (например, boost::shared_ptr). Не пытайтесь использовать std::auto_ptr для этого, он не будет работать (даже не скомпилируется).

Еще одна вещь, которую следует иметь в виду, вы должны избегать использования < для сравнения итераторов в вашем цикле, когда это возможно, это будет работать только для итераторов, которые моделируют итератор с произвольным доступом, что означает, что вы не можете изменить свой код на использовать например std::list.

8 голосов
/ 03 мая 2009

vector <c> cvect не является вектором указателей. Это вектор объектов типа c. Вы хотите vector <c*> cvect. и вы, вероятно, хотите:

cvect.push_back( new c );

А затем, учитывая итератор, вы хотите что-то вроде:

(*it)->func();

Конечно, вполне вероятно, что вам вообще не нужен вектор указателей ...

4 голосов
/ 03 мая 2009

Да, это возможно, и на самом деле необходимо использовать указатели, если вы хотите, чтобы ваш вектор содержал объекты из всей иерархии классов, а не из одного типа. (Отказ от использования указателей приведет к страшной проблеме нарезки объектов - все объекты автоматически преобразуются в тип базового класса. Это не диагностируется компилятором и почти наверняка не то, что вам нужно.)

class c
{
     void virtual func();
};

class sc:public c
{
     void func(){cout<<"using func";}
};

sc cobj;

vector<c*> cvect;             // Note the type is "c*"
cvect.push_back(&cobj);       // Note the "&"
vector<c*>::iterator citer;

for(citer=cvect.begin();citer != cvect.end();citer++)   // Use "!=" not "<"
{
     (*citer)->func();
}

Обратите внимание, что с вектором указателей вам необходимо выполнить собственное управление памятью , поэтому будьте очень осторожны - если вы будете использовать локальные объекты (как указано выше), они не должны выпадать из сфера до контейнера Если вы используете указатели на объекты, созданные с помощью new, вам потребуется delete их вручную, прежде чем контейнер будет уничтожен. В этом случае вам следует рассмотреть возможность использования интеллектуальных указателей, таких как smart_ptr, предоставленный Boost.

2 голосов
/ 03 мая 2009

Да, конечно.

// TestCPP.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <vector>


using namespace std;

class c
{
public:
    void virtual func() = 0;
};

class sc:public c
{
public:
    void func(){cout<<"using func";}
};

int _tmain(int argc, _TCHAR* argv[])
{
    sc cobj;

    vector<c*> cvect;
    cvect.push_back(&cobj);
    vector<c*>::iterator citer;

    for(citer=cvect.begin();citer<cvect.end();citer++)
    {
        (*citer)->func();
    }

    return 0;
}

Обратите внимание на объявление vector<c*> cvect и использование cvect.push_back(&cobj).

Из предоставленного кода вы используете итератор неправильно. Для доступа к члену, на который указывает итератор, вы должны использовать *citer вместо citer.

2 голосов
/ 03 мая 2009

Вы создали vector<c*> для вектора указателей. Затем используйте new для выделения памяти для объектов c и вставьте их в вектор. Кроме того, не забывайте, что вы должны delete самостоятельно, и vector.clear () не освободит память, выделенную для объектов c. Здесь вы должны хранить c как вектор указателей, иначе вызов виртуальной функции не будет работать.

0 голосов
/ 05 мая 2009

Попробуйте Библиотека контейнера указателей повышения . Он имеет несколько преимуществ перед обычным вектором указателей, например:

my_container.push_back( 0 );            // throws bad_ptr 
ptr_vector<X> pvec; 
std::vector<X*> vec;
( *vec.begin() )->foo(); // call X::foo(), a bit clumsy
pvec.begin()->foo();     // no indirection needed
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...