Software Design

Design de software em C, C++, Java, etc…

Boost Smart Pointers: scoped_ptr

O scoped_ptr é o mais simples dos smart pointers da boost. A idéia por trás deste smart pointer é garantir a exclusão do objeto assim que o scoped_ptr sair de escopo. Por exemplo, se declararmos o scoped_ptr dentro de uma função o objeto será excluído assim que o código sair da função ( através de um return, throw, etc. ).

O overhead de um scoped_ptr é mínimo já que ele só precisa armazenar a referência para o ponteiro primitivo, basicamente a mesma coisa que declarar o ponteiro diretamente no corpo da função.

Outra característica é que o scoped_ptr é non-copyable o que significa que você não pode utilizar ele em nenhuma atribuição ( = ) e nem como retorno de uma função, também não é possível ter um vector<scoped_ptr<…> > porque os objetos contidos no vector precisam ser copiados.

Como um exemplo imagine que nossa função precisa fazer uma consulta no banco de dados. Já temos o objeto connection ( que é um ponteiro ) e precisamos criar um statement. Este statement terá que ser destruído ao final da função. Sem scoped_ptr o código ficaria + ou – assim:

//...
void DataInterface::printNames() {
  db::statement *stmt = m_connection->createStatement("SELECT NAME FROM EMPLOYEE");
  if ( stmt == NULL ) {
    return;
  }
  if ( (stmt->hasError()) || (stmt->count() == 0) ) {
    delete stmt;
    return;
  }
  try {
    while ( stmt->next() ) {
      cout << stmt->string(0) << endl;
    }
  } catch (...) {
    cout << "Error" << endl;
    delete stmt;
    return;
  }
  cout << stmt->count() << " records printed" << endl;
  delete stmt;
}

Com scope_ptr ficaria assim:

//...
void DataInterface::printNames() {
  using namespace boost;
  scoped_ptr<db::statement> stmt = m_connection->createStatement("SELECT NAME FROM EMPLOYEE");
  if ( (stmt == NULL) || (stmt->hasError()) || (stmt->count() == 0) ) {
    return;
  }
  try {
    while ( stmt->next() ) {
      cout << stmt->string(0) << endl;
    }
  } catch (...) {
    cout << "Error" << endl;
    return;
  }
  cout << stmt->count() << " records printed" << endl;
}

Desta forma evitamos ter que ficar usando delete em vários pontos da função, além pudemos juntar as 2 condições de checagem de erro em uma só ( no exemplo anterior não era possível ).

Nesse exemplo a função é bastante simples e não tem muito controle de fluxo. Agora imagine uma função que tivesse vários if’s / swtich / try-catch e aí por diante. O código viraria uma bagunça.

O scoped_ptr pode ser usado também em outros escopos como de classe por exemplo. Geralmente isso é útil quando não podemos utilizar a alocação automática do objeto por qualquer motivo. Neste caso quando o objeto que contém o scoped_ptr for desalocado, o destrutor do scoped_ptr será invocado e o objeto apontado por ele será excluído.

A utilização de smart pointers em C++ é altamente recomendada, tanto que eles viraram parte do padrão C++11, por isso deve-se evitar a utilização de raw pointers ao máximo – claro que utilizando o bom senso.

Meu próximo artigo será sobre o boost::shared_ptr e boost::weak_ptr.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às setembro 19, 2012 por em boost, C++ e marcado , , , , .
%d blogueiros gostam disto: