Безопасный код

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by cupper, 22 Dec 2010.

  1. cupper

    cupper Elder - Старейшина

    Joined:
    6 Jun 2007
    Messages:
    369
    Likes Received:
    92
    Reputations:
    5
    немогу сообразить как правильно построить работу функции чтобы учесть следующие факты:
    1. переложить контроль за удаление динамически созданных объектов на умные указатели.
    2. не терять память в случае исключения
    3. правильно обрабатывать отсутствие резульата
    вот код функции, для выборки из БД некоторых данных (одно строки) превращения и в объект моего класса и возврат пользователю
    Code:
    /// получить PersonInfo по ID (ptrPersonInfo)
    	BussinesObject::ptrPersonInfo PersonDB::GetPersonInfoOnID(const int id) throw(sql::SQLException)
    	{
    		boost::shared_ptr<sql::Connection> con(Connect());
    		boost::shared_ptr<sql::PreparedStatement> prep_stmt(
    			con->prepareStatement(QueryPersoneOnID));
    		prep_stmt->setInt(1, id);
    		boost::shared_ptr<sql::ResultSet> res(prep_stmt->executeQuery());
    		PersonInfo* pers;
    		if (res->next()) {
    			pers = new PersonInfo(id, res->getString("first_name"),
    				res->getString("last_name"), res->getString("birthday"));
    
    		}
    		return ptrPersonInfo(pers);
    	}
    
    где
    Code:
    typedef boost::shared_ptr<PersonInfo> ptrPersonInfo;
    typedef std::vector<ptrPersonInfo> vecPtrPersonInfo;
    typedef boost::shared_ptr<vecPtrPersonInfo> ptrVecPtrPersonInfo;
    
    тут наблюдаются следующие проблемы:
    1. в случае если возникнет какоето исключение в этот момент
    Code:
    pers = new PersonInfo(id, res->getString("first_name"),  res->getString("last_name"), res->getString("birthday"));
    память будет утеряна. Возможно решить за счет try catch, но что делать в catch ? возвращать пустой объект или передавать исключение выше по иерархии вызова ?
    2. если выборка из БД будет пустой
    Code:
    if (res->next()) {
    то будет произведене попытка инициализации умного указателя указателем не на что
    Code:
    return ptrPersonInfo(pers);
    Возможно стоит в этом случае инициализировать shared_ptr пустым объектом, но както не красиво.

    как бы вы решили эти проблемы ?
     
  2. GRRRL Power

    GRRRL Power Elder - Старейшина

    Joined:
    13 Jul 2010
    Messages:
    823
    Likes Received:
    185
    Reputations:
    84
    Возвращай из функции auto_ptr. В конце концов, он ради этого изначально и был создан.
    PHP:
    ...
    std::auto_ptr<PersonInfopers;

    if (
    res->next()) {
                
    pers.reset(new PersonInfo(idres->getString("first_name"),
                    
    res->getString("last_name"), res->getString("birthday")));

            }
            return 
    pers;
    После вызова функции проверять, не нулевой ли указатель оттуда вернулся.

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

    А вообще, архитектура изначально неверна. Из функции нужно возвращать никакие не смартпоинтеры, а сам объект. Добавить в него конструктор без параметров и предусмотреть метод вроде is_empty(), который будет говорить, есть ли информация в этом объекте, так было бы лучше. Чем меньше new в программе, тем лучше. А уж от delete следует избавляться вообще.
     
    1 person likes this.
  3. cupper

    cupper Elder - Старейшина

    Joined:
    6 Jun 2007
    Messages:
    369
    Likes Received:
    92
    Reputations:
    5
    чем там плох возврат смарт поинтера/просто указателя (просто указателя плох тем что мы перекладываем ответственность на пользователя). И чем так хорош возврат объекта ?

    Предположим есть некий объект. Есть функция как то формирующая этот объект и возвращающая его, а не указатель на него.
    Есть функция которая возвращает список таких объектов.
    Тогда в функции формирующей список, возможно захочется использовать функцию возвращающую один объект для формирования этого списка.
    Code:
    vector<Object> vec;
    vec.push_back(GetObject());
    Тогда получается для того чтобы сформировать список, нужно вызвать конструктор копирования для каждого из создаваемых объектов... накладно.

    PS. я надеюсь ты мне щас опять мозг не взорвешь тем что и тут действует какая то оптимизация которая не копирует объект и использует тот же. Тогда придется сжечь 9/10 всех книг по С++ :)
     
    #3 cupper, 23 Dec 2010
    Last edited: 23 Dec 2010
  4. GRRRL Power

    GRRRL Power Elder - Старейшина

    Joined:
    13 Jul 2010
    Messages:
    823
    Likes Received:
    185
    Reputations:
    84
    В случае возврата объекта копирование выполняться не будет, как я уже пояснял, а вот в случае возврата списка объектов без него уже не обойтись. В твоем примере списков нет, поэтому я и посоветовал возвращать объект, чтобы не следить вообще ни за чем.
    Вообще, можно и список возвращать с минимальными копированиями. Тип list, например, будет вызывать копирование объектов только при помещении их в него.