O mundo em que Bjarne vive é muito ... acadêmico, por falta de um termo melhor. Se o seu código puder ser projetado e estruturado de modo que os objetos tenham hierarquias relacionais muito deliberadas, de modo que os relacionamentos de propriedade sejam rígidos e inflexíveis, o código fluirá em uma direção (de alto nível para baixo), e os objetos só falarão com os de baixo nível. hierarquia, então você não encontrará muita necessidade shared_ptr. É algo que você usa nessas raras ocasiões em que alguém tem que quebrar as regras. Mas, caso contrário, você pode colocar tudo em vectors ou outras estruturas de dados que usam semântica de valor unique_ptres para coisas que você deve alocar individualmente.
Embora esse seja um ótimo mundo para se viver, não é o que você pode fazer o tempo todo. Se você não pode organizar seu código dessa maneira, porque o design do sistema que você está tentando criar significa que é impossível (ou apenas profundamente desagradável), você se encontrará cada vez mais necessitando de propriedade compartilhada de objetos. .
Nesse sistema, manter ponteiros nus não é exatamente perigoso, mas levanta questões. O melhor de tudo shared_ptré que ele fornece garantias sintáticas razoáveis sobre a vida útil do objeto. Pode ser quebrado? Claro. Mas as pessoas também podem const_castcoisas; cuidados básicos e alimentação de shared_ptrdevem fornecer qualidade de vida razoável para objetos alocados cuja propriedade deve ser compartilhada.
Depois, há weak_ptrs, que não podem ser usados na ausência de a shared_ptr. Se o seu sistema estiver rigidamente estruturado, você poderá armazenar um ponteiro nu para algum objeto, seguro de que a estrutura do aplicativo garante que o objeto apontado sobreviverá a você. Você pode chamar uma função que retorne um ponteiro para algum valor interno ou externo (localize o objeto chamado X, por exemplo). No código estruturado adequadamente, essa função só estaria disponível se a vida útil do objeto exceder a sua; portanto, é bom armazenar o ponteiro nu no seu objeto.
Como essa rigidez nem sempre é possível em sistemas reais, você precisa de uma maneira de garantir razoavelmente a vida útil. Às vezes, você não precisa de propriedade total; às vezes, você só precisa saber quando o ponteiro é ruim ou bom. É aí que weak_ptrentra. Houve casos em que eu poderia ter usado um unique_ptror boost::scoped_ptr, mas tive que usar um shared_ptrporque eu precisava especificamente fornecer a alguém um ponteiro "volátil". Um ponteiro com vida útil indeterminada, e eles poderiam consultar quando esse ponteiro foi destruído.
Uma maneira segura de sobreviver quando o estado do mundo é indeterminado.
Isso poderia ter sido feito por alguma chamada de função para obter o ponteiro, em vez de via weak_ptr? Sim, mas isso poderia ser mais facilmente quebrado. Uma função que retorna um ponteiro nu não tem como sugerir sintaticamente que o usuário não faça algo como armazenar esse ponteiro a longo prazo. O retorno de um shared_ptrtambém torna muito fácil para alguém simplesmente armazená-lo e potencialmente prolongar a vida útil de um objeto. Retornar um weak_ptrno entanto sugere fortemente que armazenar o que shared_ptrvocê recebe locké uma ... idéia duvidosa. Isso não impedirá que você faça isso, mas nada no C ++ o impede de quebrar o código. weak_ptrfornece alguma resistência mínima ao fazer a coisa natural.
Agora, isso não quer dizer que shared_ptrnão possa ser usado em excesso ; certamente pode. Especialmente antes unique_ptr, havia muitos casos em que eu apenas usava um boost::shared_ptrporque precisava passar um ponteiro RAII ou colocá-lo em uma lista. Sem movimento semântica e unique_ptr, boost::shared_ptrera a única solução real.
E você pode usá-lo em locais onde é desnecessário. Como mencionado acima, a estrutura de código adequada pode eliminar a necessidade de alguns usos de shared_ptr. Mas se o seu sistema não puder ser estruturado como tal e ainda fizer o que for necessário, shared_ptrserá de uso significativo.