Вы аннотировали свой класс Dao @Transactional, но не свой класс обслуживания. Строка:
Visitor storedVisitor =
(Visitor) sessionFactory.getCurrentSession().get(Visitor.class,
visitorDetails.getTfscNumber(), LockMode.NONE);
требует, чтобы вы были в транзакции.
Вы можете исправить это, добавив аннотацию @Transactional в свой класс ProfileService или просто метод registerVisitor ().
Здесь есть несколько проблем. Самым срочным может быть то, что происходит, когда идентификатор пункта назначения не найден. Поскольку у вас нет конструктора в routing_entry
и вы не выполняете инициализацию по умолчанию, он будет иметь неопределенные значения.
// the data inside route is undefined at this point
routing_entry route;
Один из способов справиться с этим - выполнить инициализацию по умолчанию. Это работает, инструктируя компилятор заполнить структуру нулями. Это своего рода уловка, заимствованная из C, но здесь она хорошо работает.
routing_entry route={0};
Вы упомянули, что переходите с Java, в отличие от Java, члены структуры и класса не инициализируются 0, так что вам действительно нужно как-то с этим справиться. Другой способ - определить конструктор:
struct routing_entry
{
routing_entry()
: destSeq(0)
, nextHop(0)
, hopCount(0)
{ }
unsigned long destSeq; // 32 bits
unsigned long nextHop; // 32 bits
unsigned char hopCount; // 8 bits
};
Также обратите внимание, что в C ++ размер целочисленных членов и членов char не определяется в битах. Тип char - 1 байт (но байт не определен, но обычно 8 бит). В наши дни длинные числа обычно составляют 4 байта, но могут иметь другое значение.
Переходим к consultTable
с фиксированной инициализацией:
routing_entry Cnode_router_aodv::consultTable(unsigned int destinationID )
{
routing_entry route={0};
if ( routing_table.find(destinationID) != routing_table.end() )
route = routing_table[destinationID];
return route; // will be "empty" if not found
}
Один из способов узнать, может быть, это проверить, является ли структура все еще обнулен. Я предпочитаю, чтобы при рефакторинге функция возвращала bool
для индикации успеха. Кроме того, я всегда для простоты типизирую структуры STL, поэтому сделаю это здесь:
typedef map< unsigned long int, routing_entry > RoutingTable;
RoutingTable routing_table;
Затем мы передаем ссылку на запись маршрутизации для заполнения. Это может быть более эффективным для компилятора, но, вероятно, здесь это не имеет значения - в любом случае это всего лишь один метод.
bool Cnode_router_aodv::consultTable(unsigned int destinationID, routing_entry &entry)
{
RoutingTable::const_iterator iter=routing_table.find(destinationID);
if (iter==routing_table.end())
return false;
entry=iter->second;
return true;
}
Вы бы назвали его так:
routing_entry entry={0};
if (consultTable(id, entry))
{
// do something with entry
}
Лучший способ, который я нашел для этого, - использовать boost :: optional , который предназначен для решения именно этой проблемы.
Ваша функция будет выглядеть примерно так. вот так: -
boost::optional<routing_entry> consultTable(unsigned int destinationID )
{
if ( routing_table.find(destinationID) != routing_table.end() )
return routing_table[destinationID];
else
return boost::optional<routing_entry>()
}
И ваш вызывающий код выглядит как
boost::optional<routing_entry> route = consultTable(42);
if (route)
doSomethingWith(route.get())
else
report("consultTable failed to locate 42");
Как правило, использование "выходных" параметров (передача указателя - или ссылки - на объект, который затем "заполняется" вызываемой функцией, не одобряется в C ++. Подход, согласно которому все "возвращаемое" функцией содержится в возвращаемом значении и что никакие параметры функции не изменяются, может сделать код более читабельным и поддерживаемым в долгосрочной перспективе.
Это типичное решение вашей проблемы:
bool Cnode_router_aodv::consultTable(unsigned int destinationID,
routing_entry* route ) {
if ( routing_table.find(destinationID) != routing_table.end() ) {
*route = routing_table[destinationID];
return true;
}
return false;
}
Вместо указателя вы можете использовать ссылку; это вопрос стиля.
Другой способ - заставить вашу функцию возвращать значение состояния (HRESULT или подобное), указывающее, была ли она инициализирована, и передавать указатель на структуру как один из параметров.
В C ++ обычно возвращают статус, указывающий на код ошибки (или 0 в случае успеха), но это, конечно, зависит от ваших навыков программирования.
Простая передача указателя и проверка на null все равно сработает.
shared_ptr<routing_entry> Cnode_router_aodv::consultTable(unsigned int destinationID ) {
shared_ptr<routing_entry> route;
if ( routing_table.find(destinationID) != routing_table.end() )
route.reset( new routing_entry( routing_table[destinationID] ) );
return route; // will be "empty" if not found
}
// using
void Cnode_router_aodv::test()
{
shared_ptr<routing_entry> r = consultTable( some_value );
if ( r != 0 ) {
// do something with r
}
// r will be freed automatically when leaving the scope.
}
Добрый день,
Соглашаясь с большей частью того, что говорит 1800, Я был бы более склонен к тому, чтобы ваша функция consultTable возвращала указатель на структуру routing_entry, а не логическое значение.
Если запись найдена в таблице, функция возвращает указатель на новую routing_entry. Если он не найден, возвращается NULL.
BTW Хороший ответ, 1800.
HTH
приветствует,
В качестве альтернативы решению с параметрами ввода-вывода вы можете последовать совету дяди Бобса и создать класс чтения записей.
typedef map< unsigned long int, routing_entry > routing_table_type;
routing_table_type routing_table;
//Is valid as long as the entry is not removed from the map
class routing_entry_reader
{
const routing_table_type::const_iterator routing_table_entry;
const routing_table_type& routing_table;
public:
routing_entry_reader( const routing_table_type& routing_table, int destination_id )
: routing_table(routing_table),
routing_table_entry( routing_table.find(destination_id) ) {
}
bool contains_entry() const {
return routing_table_entry!=routing_table.end();
}
const routing_entry& entryByRef() const {
assert(contains_entry());
return routing_table_entry->second;
}
};
routing_entry_reader entry_reader(routing_table, destination_id);
if( entry_reader.contains_entry() )
{
// read the values from the entry
}
Прежде всего обратите внимание, что в C ++, в отличие от Java, пользователи могут определять типы значений. Это означает, что существует 2 ^ 32 * 2 ^ 32 * 2 ^ 8 возможных значений для routing_entry. Если хотите, вы можете представить себе routing_entry как 72-битный примитивный тип, хотя с аналогией следует быть осторожнее.
Итак, в Java route
может быть нулевым, и есть 2 ^ 32 * 2 ^ 32 * 2 ^ 8 + 1 полезные значения для переменной routing_entry
. В 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 заполняет ответ и возвращает значение, показывающее, удалось это или нет. Обычно это называется «выходным параметром», потому что он имитирует функцию, возвращающую routing_entry
и логическое значение.
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;
В вашем методе
routing_entry Cnode_router_aodv::consultTable(unsigned int destinationID ) {
routing_entry route;
...
return route;
}
вы пытаетесь вернуть автоматический, т.е. объект находится в кадре локального стека, объект. Это никогда не сделает то, что вы хотите, так как эта память недоступна, когда функция выходит за пределы области видимости.
Вам нужно будет создать объект, а затем вернуть вновь созданный объект. Я предлагаю вам проконсультироваться со Скоттом Мейерсом по Эффективному C ++, третье издание, № 21.