Можно ли передать итератор из вектора указателей по ссылке на другую функцию?

avatar
Squire1998
8 апреля 2018 в 11:37
94
2
0

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

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

Я использую алгоритм сортировки, который сравнивает элемент данных total_dist, в котором хранится суммарное расстояние, пройденное каждым объектом.

Из-за более ранней проблемы мне пришлось явно инициализировать элемент данных total_dist равным 0 для каждого объекта в векторе.

Из-за этого алгоритм сортировки "видит" только инициализированное значение (т.е. 0), что означает, что вектор не перестраивается.

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

Однако я не уверен, что это синтаксически возможно. Это то, что у меня сейчас есть (я знаю, что мой код, вероятно, действительно уродлив и неэлегантен, но я все еще новичок в программировании в целом).

Метод

    void Vehicle::set_total_dist(float &f) {
    total_dist += f;           //total_dist is public Vehicle data member
    }

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

Инициализация вектора

    vector<Vehicle*> vehicle_lanes; // 'Vehicle' is the parent class        

    // Populating vector with respective child vehicle objects
    vehicle_lanes.push_back(new Car);       
    vehicle_lanes.push_back(new Van);
    vehicle_lanes.push_back(new Bus);
    vehicle_lanes.push_back(new Lorry);
    vehicle_lanes.push_back(new Motorbike);

    // Setting child object names for identification
    vehicle_lanes[0]->set_name("Car");
    vehicle_lanes[1]->set_name("Van");      
    vehicle_lanes[2]->set_name("Bus");
    vehicle_lanes[3]->set_name("Lorry");
    vehicle_lanes[4]->set_name("Motorbike");

    // Initialising total distance travelled by each object to 0 meters
    vehicle_lanes[0]->total_dist = 0;       
    vehicle_lanes[1]->total_dist = 0;       
    vehicle_lanes[2]->total_dist = 0;
    vehicle_lanes[3]->total_dist = 0;
    vehicle_lanes[4]->total_dist = 0;

Если total_dist явно не инициализировано, начальное суммированное значение не определено, поэтому set_total_dist() вычисляет то, что, как мне кажется, является своего рода буквенно-цифровым значением ошибки.

Векторный итератор и алгоритм сортировки

    for (vector<Vehicle*>::iterator it = vehicle_lanes.begin(); it != 
    vehicle_lanes.end(); it++) {
        
        // Vehicle sort function
        sort(vehicle_lanes.begin(), vehicle_lanes.end(), 
        CompareVehicleLocation);

        // This is the problem// 
        (*it)->set_total_dist((*it)->get_grid_location());

        // Printing the object name and it's associated Total_dist
        cout << (*it)->get_name() << "'s total distance travelled is: " << 
        (*it)->get_total_dist() << " units." << endl;
    }

Компилятору не нравится, когда я передаю (*it)->get_grid_location() по ссылке, но компилируется нормально, когда я передаю аргумент по значению. При попытке передать ссылку среда IDE показывает красную подчеркивание между двойными левыми круглыми скобками ((.

.

Ошибка, которую я получаю перед компиляцией при попытке пройти по ссылке:

начальное значение ссылки на неконстантное должно быть lvalue

После компиляции я получаю:

Ошибка C2664 'void Vehicle::set_total_dist(float &)': невозможно преобразовать аргумент 1 от 'float' до 'float &'

Я пробовал искать сообщения, идентичные моим, но мне не повезло, обнаруженные мной проблемы были в некоторой степени связаны с моими, например Что не так с передачей итератора C++ по ссылке? . Для меня это не имело особого смысла из-за моей неопытности.

Будем очень признательны за любые советы. Я буду рад предоставить любую дополнительную, относящуюся к делу информацию, которую я могу. Спасибо.

Источник
HolyBlackCat
8 апреля 2018 в 11:40
1

Нет смысла передавать его по ссылке, вы его не модифицируете в функции.

Some programmer dude
8 апреля 2018 в 11:41
0

Что касается ошибки, я предполагаю, что get_grid_location() возвращает float по значению<75425558759456>?

Squire1998
8 апреля 2018 в 11:42
0

@HolyBlackCat Насколько я понимаю, передача по ссылке навсегда изменяет ее в функции. Что я и собираюсь сделать. Есть ли альтернативы, которые вы могли бы предложить, если мой текущий подход не имеет смысла?

Squire1998
8 апреля 2018 в 11:43
0

@Someprogrammerdude да, это правильно

HolyBlackCat
8 апреля 2018 в 11:49
0

Да, вам понадобится ссылка, если вы изменили f. Но это не так.

Squire1998
8 апреля 2018 в 11:54
0

@HolyBlackCat ааа, понятно. Я, очевидно, думаю обо всем этом неправильно. Спасибо. В любом случае, если бы вы просто посмеялись над моим невежеством, как бы я синтаксически передал итератор по ссылке на функцию? Я думаю, что мне нужно будет сделать это в конце концов, поэтому мне не нужно знать.

HolyBlackCat
8 апреля 2018 в 12:11
0

Как и для любого другого типа: void foo(vector<Vehicle*>::iterator &blah) {...}

Ответы (2)

avatar
seccpur
8 апреля 2018 в 15:20
0

Я обнаружил пару проблем в вашей программе:

1) Требуется некоторое упрощение. Вам не нужно устанавливать vehicle name, если он интегрирован с конструктором.

2) Переменная-член total_distance может быть инициализирована нулем в самом определении класса.

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

4) Используйте ключевое слово auto для замены длинных имен типов.

Попробуйте это (я использую фиктивный генератор расстояний, так как ваша логика сетки не так ясна):

#include <iostream>
#include <vector>
#include <algorithm>


using namespace std;


class Vehicle
{
protected:
    string name;
    int total_dist{0};   // distance will be set to 0 on any new vehicle
public:
    Vehicle() {}
    ~Vehicle() {}
    virtual string get_name() = 0;
    int get_total_dist() const { return total_dist; }
    void set_grid_location(int d) {total_dist = d;}
};

class Car :public Vehicle 
{
public:
    Car() 
    {
        name = "Car";  //name will be automatically set
    }

    string get_name() { return name; }
};

class Bus :public Vehicle
{
public:
    Bus()
    {
        name = "Bus";
    }

    string get_name() { return name; }
};

int location_generator() // testing only - use your own method
{
    int arr[] = {4,2,1,5,6,2,3 };
    static int count = 0;

    return arr[count++ % 6];
}

int main()
{
    vector<Vehicle*> vehicle_lanes;       

    //create some vehicles
    vehicle_lanes.push_back(new Car);
    vehicle_lanes.push_back(new Bus);

    //filling the location of vehicles before sorting
    for (auto& it = vehicle_lanes.begin(); it != vehicle_lanes.end(); it++)  
    {
        (*it)->set_grid_location(location_generator());
    }

    //sorting
    auto CompareVehicleLocation = [](const Vehicle* lhs, const Vehicle* rhs)->bool { return lhs->get_total_dist() < rhs->get_total_dist(); };

    sort(vehicle_lanes.begin(), vehicle_lanes.end(), CompareVehicleLocation);


    //printing sorted vector
    for (auto& it = vehicle_lanes.begin(); it != vehicle_lanes.end(); it++)
    {
        cout << (*it)->get_name().c_str() << "'s total distance travelled is: " <<
            (*it)->get_total_dist() << " units." << endl;
    }

    //delete the pointers to avoid memory leak at the end
    for (auto& it = vehicle_lanes.begin(); it != vehicle_lanes.end(); it++)
    {
       delete (*it);
    }
    return 0;
}
avatar
scinart
8 апреля 2018 в 11:53
0

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

Ваша ошибка cannot convert from 'float' to 'float &' заключается в передаче правого значения float функции, которая принимает ссылку на левое значение (float&). Это означает, что ваша функция предположительно изменит параметр, который она принимает. Но правое значение не имеет адреса и, следовательно, не может быть изменено. Вот почему компилятор отказывается от ваших кодов.

Еще один сбой заключается в том, что функция сортировки в вашем коде должна быть вне цикла for.