Возврат структуры от функции, как я могу проверить, что это инициализируется?

Вы аннотировали свой класс Dao @Transactional, но не свой класс обслуживания. Строка:

Visitor storedVisitor =
    (Visitor) sessionFactory.getCurrentSession().get(Visitor.class,
            visitorDetails.getTfscNumber(), LockMode.NONE);

требует, чтобы вы были в транзакции.

Вы можете исправить это, добавив аннотацию @Transactional в свой класс ProfileService или просто метод registerVisitor ().

5
задан Rob Wells 19 June 2009 в 11:14
поделиться

9 ответов

Здесь есть несколько проблем. Самым срочным может быть то, что происходит, когда идентификатор пункта назначения не найден. Поскольку у вас нет конструктора в 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
}
15
ответ дан 18 December 2019 в 07:31
поделиться

Лучший способ, который я нашел для этого, - использовать 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 ++. Подход, согласно которому все "возвращаемое" функцией содержится в возвращаемом значении и что никакие параметры функции не изменяются, может сделать код более читабельным и поддерживаемым в долгосрочной перспективе.

3
ответ дан 18 December 2019 в 07:31
поделиться

Это типичное решение вашей проблемы:

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;
}

Вместо указателя вы можете использовать ссылку; это вопрос стиля.

2
ответ дан 18 December 2019 в 07:31
поделиться

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

В C ++ обычно возвращают статус, указывающий на код ошибки (или 0 в случае успеха), но это, конечно, зависит от ваших навыков программирования.

Простая передача указателя и проверка на null все равно сработает.

0
ответ дан 18 December 2019 в 07:31
поделиться

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.
}

0
ответ дан 18 December 2019 в 07:31
поделиться

Добрый день,

Соглашаясь с большей частью того, что говорит 1800, Я был бы более склонен к тому, чтобы ваша функция consultTable возвращала указатель на структуру routing_entry, а не логическое значение.

Если запись найдена в таблице, функция возвращает указатель на новую routing_entry. Если он не найден, возвращается NULL.

BTW Хороший ответ, 1800.

HTH

приветствует,

0
ответ дан 18 December 2019 в 07:31
поделиться

В качестве альтернативы решению с параметрами ввода-вывода вы можете последовать совету дяди Бобса и создать класс чтения записей.

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
}
0
ответ дан 18 December 2019 в 07:31
поделиться

Прежде всего обратите внимание, что в 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;
1
ответ дан 18 December 2019 в 07:31
поделиться

В вашем методе

routing_entry Cnode_router_aodv::consultTable(unsigned int destinationID ) {

    routing_entry route;
    ...
    return route;
}

вы пытаетесь вернуть автоматический, т.е. объект находится в кадре локального стека, объект. Это никогда не сделает то, что вы хотите, так как эта память недоступна, когда функция выходит за пределы области видимости.

Вам нужно будет создать объект, а затем вернуть вновь созданный объект. Я предлагаю вам проконсультироваться со Скоттом Мейерсом по Эффективному C ++, третье издание, № 21.

0
ответ дан 18 December 2019 в 07:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: