Первое замечание: в C ++, в отличие от Java, пользователи могут определять типы значений. Это означает, что существует 2 ^ 32 * 2 ^ 32 * 2 ^ 8 возможных значений для routing_entry. Если вы хотите, вы можете думать о routing_entry как о 72-битном примитивном типе, хотя вы должны быть немного осторожны с аналогией.
Таким образом, в Java route
может быть нулевым, и для переменной routing_entry
есть 2 ^ 32 * 2 ^ 32 * 2 ^ 8 + 1 полезных разных значений. В C ++ он не может быть нулевым. В Java «пустой» может означать возврат пустой ссылки. В C ++ только указатели могут быть нулевыми, а routing_entry
не является типом указателя. Так что в вашем коде в данном случае «пустой» означает «я понятия не имею, какое значение имеет эта вещь, потому что я никогда ее не инициализировал и не присвоил».
В Java объект routing_entry
будет размещен в куче. В C ++ вы не хотите делать это без необходимости, потому что управление памятью в C ++ требует усилий.
У вас есть несколько (хороших) вариантов:
1) добавить поле в запись маршрутизации, чтобы указать, что оно было инициализировано. Скорее всего, это не сделает структуру больше из-за требований вашей реализации к отступам и выравниванию:
struct routing_entry {
unsigned long destSeq; // 32 bits on Win32. Could be different.
unsigned long nextHop // 32 bits on Win32. Could be different.
unsigned char hopCount; // 8 bits on all modern CPUs. Could be different.
unsigned char initialized; // ditto
};
Почему бы не использовать bool? Потому что стандарт услужливо позволяет sizeof(bool) != 1
. Вполне возможно, что bool реализован как int, особенно если у вас старый компилятор C ++. Это сделало бы вашу структуру больше.
Затем убедитесь, что структура содержит 0 значений в вашей функции, а не мусор в стеке:
routing_entry Cnode_router_aodv::consultTable(unsigned int destinationID ) {
routing_entry route = {};
if ( routing_table.find(destinationID) != routing_table.end() )
route = routing_table[destinationID];
return route; // will be "empty" if not found
}
И убедитесь, что у всех входов в карте инициализированное поле установлено в ненулевое значение. Вызывающий затем проверяет инициализацию.
2) Использовать «магические» значения существующих полей в качестве маркеров.
Предположим, что вы никогда не имеете дело с маршрутами с hopCount 0. Затем, пока вы инициализируете 0, как описано выше, вызывающие могут проверять hopCount! = 0. Максимальные значения типов также являются хорошими значениями флагов поскольку вы ограничиваете свои маршруты 256 прыжками, скорее всего, вы не будете причинять никакого вреда, ограничив их 255 прыжками. Вместо того, чтобы вызывать это нужно, добавьте метод в структуру:
struct routing_entry {
unsigned long destSeq; // 32 bits
unsigned long nextHop // 32 bits
unsigned char hopCount; // 8 bits
bool routeFound() { return hopCount != (unsigned char)-1; }
};
Тогда вы бы инициализировали так:
routing_entry route = {0, 0, -1};
или, если вас беспокоит, что произойдет, если вы в будущем измените порядок или количество полей:
routing_entry route = {0};
route.hopCount = -1;
А звонящий делает:
routing_entry myroute = consultTable(destID);
if (myroute.routeFound()) {
// get on with it
} else {
// destination unreachable. Look somewhere else.
}
3) Вызывающий абонент передает routing_entry
по указателю или неконстантной ссылке. Callee заполняет ответ и возвращает значение, указывающее, успешно ли оно выполнено или нет. Обычно это называется «out param», потому что он имитирует функцию, возвращающую routing_entry
и a bool.
bool consultTable(unsigned int destinationID, routing_entry &route) {
if ( routing_table.find(destinationID) != routing_table.end() ) {
route = routing_table[destinationID];
return true;
}
return false;
}
Звонящий делает:
routing_entry route;
if (consultTable(destID, route)) {
// route found
} else {
// destination unreachable
}
Кстати, при использовании карты ваш код в том виде, как он есть, дважды ищет идентификатор. Вы можете избежать этого
следующим образом, хотя вряд ли это заметно повлияет на производительность вашего приложения:
map< unsigned long int, routing_entry >::iterator it =
routing_table.find(destinationID);
if (it != routing_table.end()) route = *it;