unique_ptr e shared_ptr

70 views
Skip to first unread message

Gianni Rossi

unread,
Dec 16, 2010, 10:18:49 AM12/16/10
to ccppb...@googlegroups.com

Caros,

Estou com uma dúvida que meu Google-FU não consegue resolver. Como faço para criar uma função que em um dos parâmetros ela aceite um ponteiro que seja unique_ptr ou shared_ptr? Não que um template que aceite os dois, nem queria ter que fazer overloads para cada um:

void myFunc( std::any_ptr<MyClass> );

int main()

{

myFunc( std::shared_ptr<MyClass>( new MyClass() ));

myFunc( std::unique_ptr<MyClass>( new MyClass() ));

}

Alguém sabe?

Tks.

Thiago Adams

unread,
Dec 16, 2010, 10:40:50 AM12/16/10
to ccppbrasil
O melhor é não usar shared_ptr e nem unique_ptr como argumentos,
exceto se a lógica da função depender do smart pointer e não apenas do
objeto apontado.

Se a função depender só do objeto apontado então use referência para o
objeto como argumento.

Se a sua função depender das questões de ownership, os dois objetos
(shared_ptr e unique_ptr) foram criados para soluções diferentes,
então eu acho difícil você ter este caso na prática.
Se este caso realmente existisse teria que haver polimorfismo no smart
pointer e é algo que justamente não se deseja.



Gianni Rossi

unread,
Dec 16, 2010, 10:51:18 AM12/16/10
to ccppb...@googlegroups.com

Então, o caso de uso é uma API que não conhece o resto do programa, logo não consigo determinar neste ponto se devo usar shared ou unique. Outra coisa, é que a API é task-based, e dependendo do caso, ela pode executar imediatamente (cache-hit) ou agendar algo p/ ser executado mais tarde e uma thread ainda não determinada (cache-miss); logo, eu não posso usar referência.

Thiago Adams

unread,
Dec 16, 2010, 10:59:39 AM12/16/10
to ccppbrasil
Não ficou claro para mim.

A função precisa ter uma especificação independente do resto da API.
Caso contrário ela seria template.

Qual é a especificação?

O argumento é IN ? É OUT? É IN OUT? É optional? (aceita null)
O argumento vai ser compartilhado? (outro shared_ptr vai apontar pro
argumento?)
O argumento vai ser transferido? (outro unique_ptr vai apontar para o
argumento?)

Com estas perguntas respondias é que se sabe se a função depende do
objeto apontado ou se a função depende do smart pointer.
Ela pode depender só do smart pointer, só do objeto ou de ambos.

Vinícius dos Santos Oliveira

unread,
Dec 16, 2010, 11:13:30 AM12/16/10
to ccppb...@googlegroups.com
Acho que um template é a opção mais adequada ao seu caso. Caso você não possa utilizar templates posso pensar em meia dúzia de gambiarras e apresentá-las. Primeira delas:

class any_pointer
{
public:
  any_pointer(std::unique_pointer<MyClass> &p): u(&p), s(NULL) {}
  any_pointer(std::shared_pointer<MyClass> &p): u(NULL), s(&p) {}

  operator std::unique_pointer<MyClass>()
  {
    if (u)
      return *u;
    else
      return std::unique_pointer<MyClass>();
  }

  operator std::shared_pointer<MyClass>()
  {
    if (s)
      return *s;
    else
      return std::shared_pointer<MyClass>();
  }

private:
  std::unique_pointer<MyClass> *u;
  std::shared_pointer<MyClass> *s;
};

void myFunc(any_pointer);

--
Antes de enviar um e-mail para o grupo leia:
http://www.ccppbrasil.org/wiki/Lista:AntesdePerguntar
--~--~---------~--~----~---------------------------------~----------~--~----~
[&] Colabore com a Pesquisa de Preferência de Conteúdo
para Eventos do Grupo C & C++ Brasil:
http://www.surveymonkey.com/s/GBBGTXN
------~----~-------~---~---~---~---~----------------~------------~---------~
[&] C & C++ Brasil - http://www.ccppbrasil.org/
Para sair dessa lista, envie um e-mail para ccppbrasil-...@googlegroups.com
Para mais opções, visite http://groups.google.com/group/ccppbrasil
--~--~---------~--~----~--~-~--~---~----~-----------------~--~----------~
Emprego & carreira: vag...@ccppbrasil.org
http://groups.google.com/group/dev-guys?hl=en



--
Vinícius dos Santos Oliveira

Linux user #481186
Member of COMPE - Laboratório de Computação Pervasiva.

Instituto da Computação at Universidade Federal de Alagoas
Maceió, Alagoas, Brazil

"The man who has no imagination has no wings" -Muhammad Ali
"Freedom is the oxygen of the soul" -Moshe Dayan
"Without freedom, no one really has a name" -Milton Acorda

Felipe Magno de Almeida

unread,
Dec 16, 2010, 11:23:31 AM12/16/10
to ccppb...@googlegroups.com
2010/12/16 Vinícius dos Santos Oliveira <vini.i...@gmail.com>:

> Acho que um template é a opção mais adequada ao seu caso. Caso você não
> possa utilizar templates posso pensar em meia dúzia de gambiarras e
> apresentá-las. Primeira delas:
>
> class any_pointer
> {
> public:
>   any_pointer(std::unique_pointer<MyClass> &p): u(&p), s(NULL) {}
>   any_pointer(std::shared_pointer<MyClass> &p): u(NULL), s(&p) {}
>
>   operator std::unique_pointer<MyClass>()
>   {
>     if (u)
>       return *u;
>     else
>       return std::unique_pointer<MyClass>();
>   }
>
>   operator std::shared_pointer<MyClass>()
>   {
>     if (s)
>       return *s;
>     else
>       return std::shared_pointer<MyClass>();
>   }
>
> private:
>   std::unique_pointer<MyClass> *u;
>   std::shared_pointer<MyClass> *s;
> };
>
> void myFunc(any_pointer);

Por favor não faça isso. Você não está transferindo ownership do
objeto em unique_ptr
e nem mantendo ownership compartilhado com shared_ptr. O que é
bastante contra-intuitivo.

--
Felipe Magno de Almeida

Gianni Rossi

unread,
Dec 16, 2010, 11:26:11 AM12/16/10
to ccppb...@googlegroups.com

O argumento é IN, obrigatório e não-null. O objeto não vai ser transferido. Não sei dizer se vai ser compartilhado ou não. O tempo de vida dele é indeterminado (ele pode morrer ao final da função ou não). Mas fique tranquillo. Eu já olhei bem a especificação, pensei muito na arquitetura, e pensei que se houver como fazer isso, seria a solução mais simples. A que tenho, é sempre converter o unique em shared. Não queria ter que fazer isso.

Gianni Rossi

unread,
Dec 16, 2010, 11:31:33 AM12/16/10
to ccppb...@googlegroups.com

Eu pensei em algo assim, que é na linha da gambiarra mesmo:

template<class T> class any_ptr
{
protected:
std::shared_ptr<T> m_shared;
std::unique_ptr<T> m_unique;

public:
any_ptr( std::shared_ptr<T> shared ): m_shared( shared ) {};
any_ptr( std::unique_ptr<T> unique): m_unique( unique ) {};

T* operator->() const { if ( m_shared ) return m_shared.get(); else return m_unique.get(); }
T* get() const { if ( m_shared ) return m_shared.get(); else return m_unique.get(); }
};


class MyClass
{
public:
MyClass(int i): x(i) {}

int x;
};


void myfunc( any_ptr<MyClass> myObj )
{
std::cout << myObj->x << "\n";
}

int main(int argc, char **argv)
{
std::shared_ptr<MyClass> shared( new MyClass(4) );
std::unique_ptr<MyClass> unique( new MyClass(2) );

myfunc( shared );
myfunc( unique );

return 0;
}

Adriano dos Santos Fernandes

unread,
Dec 16, 2010, 11:31:34 AM12/16/10
to ccppb...@googlegroups.com
On 16/12/2010 13:18, Gianni Rossi wrote:
> Algu�m sabe?

Na minha opini�o, a melhor maneira � criar uma classe base (interface):

class MyClassHolder
{
public:
virtual ~MyClassHolder() {}

virtual MyClass* get() = 0;
};

E um template MyClassHolderImpl que aceite os dois tipos de smart pointer.

As classes da sua biblioteca armazenar�o uma MyClassHolder com o smart
pointer necess�rio ao funcionamento do pr�prio c�digo. Quem vai se
encarregar de lidar com o smart pointer do chamador ser� a
MyClassHolderImpl.


Adriano

Thiago Adams

unread,
Dec 16, 2010, 11:32:28 AM12/16/10
to ccppbrasil

> O argumento é IN, obrigatório e não-null.  
-Referencia?

>O objeto não vai ser transferido.  
Então para que smart_ptr?

>Não sei dizer se vai ser compartilhado ou não.  
Otimo, e a função precisa saber disso?


>O tempo de vida dele é indeterminado (ele pode morrer ao final da função ou não).  
-E a função precisa decidir isso? Tem algo dinamico nela que decide?





Felipe Magno de Almeida

unread,
Dec 16, 2010, 11:32:51 AM12/16/10
to ccppb...@googlegroups.com
2010/12/16 Gianni Rossi <nasus....@gmail.com>:

> On Thursday, December 16, 2010 13:59:39 Thiago Adams wrote:
>
> O argumento é IN, obrigatório e não-null.  O objeto não vai ser transferido.  Não sei dizer se vai ser compartilhado ou não.  O tempo de vida dele é indeterminado (ele pode morrer ao final da função ou não).  Mas fique tranquillo.  Eu já olhei bem a especificação, pensei muito na arquitetura, e pensei que se houver como fazer isso, seria a solução mais simples.  A que tenho, é sempre converter o unique em shared.  Não queria ter que fazer isso.

Não acho tão ruim não. Provavelmente melhor que duplicar o código
binário (template) todo para shared_ptr/unique_ptr.
Qualquer outra alternativa de type-erase será tão eficiente ou pior
que shared_ptr.

> --

Felipe Magno de Almeida

unread,
Dec 16, 2010, 11:36:35 AM12/16/10
to ccppb...@googlegroups.com
2010/12/16 Thiago Adams <thiago...@gmail.com>:

Peraí, a função não obtém ownership (compartilhado ou não) do objeto?
Se essa função pode ser executada posteriormente é bom tomar cuidado
como o seu usuário poderia fazer usso dessa função, ter que lidar com
tempo de vida manualmente de objetos junto com implementation
details de quando/como/onde essa função é escalonada etc é bem complicado.

Gianni Rossi

unread,
Dec 16, 2010, 11:38:30 AM12/16/10
to ccppb...@googlegroups.com
On Thursday, December 16, 2010 14:31:34 Adriano dos Santos Fernandes wrote:
> On 16/12/2010 13:18, Gianni Rossi wrote:
> > Alguém sabe?
>
> Na minha opinião, a melhor maneira é criar uma classe base (interface):

>
> class MyClassHolder
> {
> public:
> virtual ~MyClassHolder() {}
>
> virtual MyClass* get() = 0;
> };
>
> E um template MyClassHolderImpl que aceite os dois tipos de smart pointer.
>
> As classes da sua biblioteca armazenarão uma MyClassHolder com o smart
> pointer necessário ao funcionamento do próprio código. Quem vai se
> encarregar de lidar com o smart pointer do chamador será a
> MyClassHolderImpl.
>
Sim, justamente a opção que pensei. Só queria saber se tinha algo no std:: ou boost:: que fizesse isso de forma mais padrão.

Gianni Rossi

unread,
Dec 16, 2010, 11:51:39 AM12/16/10
to ccppb...@googlegroups.com
Correção (esse compila e funciona, mas é 'feio'):

template<class T> class any_ptr
{
protected:
std::shared_ptr<T> m_shared;
std::unique_ptr<T> m_unique;

public:
any_ptr( std::shared_ptr<T> shared ): m_shared( shared ) {};

any_ptr( std::unique_ptr<T>&& unique): m_unique( std::move( unique )) {};

T* operator->() const { if ( m_shared ) return m_shared.get(); else return m_unique.get(); }
T* get() const { if ( m_shared ) return m_shared.get(); else return m_unique.get(); }
};


class MyClass
{
public:
MyClass(int i): x(i) {}

int x;
};


void myfunc( const any_ptr<MyClass>& myObj )


{
std::cout << myObj->x << "\n";
}

int main(int argc, char **argv)
{
std::shared_ptr<MyClass> shared( new MyClass(4) );
std::unique_ptr<MyClass> unique( new MyClass(2) );

myfunc( shared );
myfunc( std::move( unique ));

return 0;
}


Thiago R. Adams

unread,
Dec 16, 2010, 11:59:32 AM12/16/10
to ccppb...@googlegroups.com
Este exemplo é o caso que eu disse que a função só depende do objeto e
não depende do smartpointer.

>void myfunc( const any_ptr<MyClass>& myObj )
> {
>        std::cout << myObj->x << "\n";
> }

Você tem um exemplo mais parecido com a realidade?
Você tem uma condição dinamica de transferencia?

seria algo assim?

void myfunc( const any_ptr<MyClass>& myObj )
{

if (condicao1)
{
//vai ser transferido para um share_ptr
}
else if (condicao2)
{
//vai ser transferido para um unique_ptr
}
else if (condicao3)
{
// nao vai acontecer nada com myobjt
}
else
{
//vai ser deletado aqui
}
}

Gianni Rossi

unread,
Dec 16, 2010, 12:06:28 PM12/16/10
to ccppb...@googlegroups.com
On Thursday, December 16, 2010 14:59:32 Thiago R. Adams wrote:
> Este exemplo é o caso que eu disse que a função só depende do objeto e
> não depende do smartpointer.
>
> >void myfunc( const any_ptr<MyClass>& myObj )
> > {
> > std::cout << myObj->x << "\n";
> > }
>
> Você tem um exemplo mais parecido com a realidade?
> Você tem uma condição dinamica de transferencia?
>
> seria algo assim?

Não. Nada do tipo. Tenho uma fila de tarefas. Cada tarefa é um pedido que pode ser um 'get' ou um 'put'. No caso do 'get', eu posso verificar se já tenho o dado local (neste caso retorna imediatamente) ou se tenho que agendar para pegar via I/O (vai rodar numa thread indeterminada). Os 'gets' compartilham o objeto, pois lá será preenchido o valor que será usado. O put é sempre assíncrono, e não compartilha o objeto.

Todo o código disso está espalhado por vários arquivos, e o ponto onde preciso do any_ptr é a central de gerenciamento de tarefas; que não conhece mais ninguém, por isso não sabe dizer nem se o objeto é um 'get' ou 'put'.

Thiago R. Adams

unread,
Dec 16, 2010, 12:21:45 PM12/16/10
to ccppb...@googlegroups.com
>Tenho uma fila de tarefas.

>Cada tarefa é um pedido que pode ser um 'get' ou um 'put'.

>No caso do 'get', eu posso verificar se já tenho o dado local (neste caso retorna imediatamente) ou se tenho que agendar para pegar via I/O (vai rodar numa thread indeterminada).  Os 'gets' compartilham o objeto, pois lá será preenchido o valor que será usado.

> O put é sempre assíncrono, e não compartilha o objeto.

Com esta explicação me parece que seu polimorfismo é (ou deveria ser )
em torno da classe base "Tarefa".
Você tem uma lista de tarefas, algumas são get e outras put.
A tarefa é uma classe que guarda o recurso.
Então porque não ter uma TarefaGet com um shared_ptr dentro e ter uma
TarefaPut com unique_ptr dentro?

Outra coisa:
O fato de algo ser compartilhado não indica que se deva usar o shared_ptr.
O shared_ptr deve ser usado quando é indeterminado quem deve deletar o
objeto. (nao sei se eh seu caso ou nao)

Se o tempo de vida é determinado , exemplo o recurso R é usado por A e
B, e A sempre vive mais que B, entao nao eh preciso usar shared_ptr.

Gianni Rossi

unread,
Dec 16, 2010, 12:34:15 PM12/16/10
to ccppb...@googlegroups.com
On Thursday, December 16, 2010 15:21:45 Thiago R. Adams wrote:
> >Tenho uma fila de tarefas.
>
> >Cada tarefa é um pedido que pode ser um 'get' ou um 'put'.
>
> >No caso do 'get', eu posso verificar se já tenho o dado local (neste caso retorna imediatamente) ou se tenho que agendar para pegar via I/O (vai rodar numa thread indeterminada). Os 'gets' compartilham o objeto, pois lá será preenchido o valor que será usado.
>
> > O put é sempre assíncrono, e não compartilha o objeto.
>
> Com esta explicação me parece que seu polimorfismo é (ou deveria ser )
> em torno da classe base "Tarefa".
> Você tem uma lista de tarefas, algumas são get e outras put.
> A tarefa é uma classe que guarda o recurso.
> Então porque não ter uma TarefaGet com um shared_ptr dentro e ter uma
> TarefaPut com unique_ptr dentro?

Então... isso é *outra* forma de fazer. Eu queria algo como o any_ptr que eu propus, pois assim, qualquer outro novo tipo de tarefa será aceito de imediato. A idéia é não ter que criar uma nova classe para cada caso. Tenho GETs e PUTs hoje. No futuro posso ter QUERY, PRE-FETCH/PREPARE, etc... Não quero ter que me preocupar com isso. Quero uma interface que aceite tudo sem impor muita coisa.

> Outra coisa:
> O fato de algo ser compartilhado não indica que se deva usar o shared_ptr.
> O shared_ptr deve ser usado quando é indeterminado quem deve deletar o
> objeto. (nao sei se eh seu caso ou nao)

Não é determinado. Não sei se ficou claro, mas eu sei sim os casos de uso do shared_ptr e unique_ptr. Essa não é a questão. Não é se devo, ou quando ou algo assim. O ponto é que eu criei algo que pode ter que interagir com os dois tipos; e eu queria saber se o std:: ou boost:: já previa isso.

P.

unread,
Dec 16, 2010, 1:54:35 PM12/16/10
to ccppbrasil
A (última revisão do rascunho da) especificação de std::shared_ptr
inclui:

template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
template<class Y> shared_ptr(auto_ptr<Y>&& r);

Agora, resta saber se a sua implementação está de acordo...

--
P.

Gianni

unread,
Dec 16, 2010, 2:46:39 PM12/16/10
to ccppb...@googlegroups.com

Putz! Isso sim responde minha pergunta.

Mas não, o meu shared_ptr não tem isso ainda.

Tks!

Thiago Adams

unread,
Dec 17, 2010, 6:44:04 AM12/17/10
to ccppbrasil

>> Então porque não ter uma TarefaGet com um shared_ptr dentro e ter uma
>> TarefaPut com unique_ptr dentro?


>Então... isso é *outra* forma de fazer.
>Eu queria algo como o any_ptr que eu propus, pois assim,
>qualquer outro novo tipo de tarefa será aceito de imediato.

>A idéia é não ter que criar uma nova classe para cada caso. Tenho GETs e PUTs hoje.
>No futuro posso ter QUERY, PRE-FETCH/PREPARE, etc...
>Não quero ter que me preocupar com isso.
>Quero uma interface que aceite tudo sem impor muita coisa.

Eu não tenho como afirmar sem ver o código, mas não importa quantas
tarefas diferentes você tenha,
cada uma tem que decidir a forma como vai armazenar o recurso.

No seu problema parece que existem 2 casos.

1) A tarefa é a unica dona do recurso
2) A tarefa compartilha o recurso.

Então tarefas novas podem derivar de uma base do tipo 1 ou 2 e não
se preocupar mais com os detalhes de como o recurso é armazenado,
apenas implementar como o recurso é usado.

A outra opção o "any_ptr" é muito problemático em design, uso,
clareza, performance etc..,

Um ponteiro não pode ser unique_ptr e shared_prt ao mesmo tempo.
Você tem tipo uma union, só pode ser um ou outro.

Porém na implementação você gasta memória para os 2 (shared_ptr e
unique_ptr)
Então qual é a vantagem comparado com ter apenas um shared_ptr?

As primeiras propostas do any_ptr já tinham o sentimento de que era
uma gambiarra.
É uma gambiarra!
Ninguém mais acha isso?

Felipe Magno de Almeida

unread,
Dec 17, 2010, 6:56:29 AM12/17/10
to ccppb...@googlegroups.com
2010/12/17 Thiago Adams <thiago...@gmail.com>:
>

[snip]

> As primeiras propostas do any_ptr já tinham o sentimento de que era
> uma gambiarra.
> É uma gambiarra!
> Ninguém mais acha isso?

Nem sempre é. Bom, acho o nome any_ptr ruim. Pois ali ele
implica union-like. E any_ptr me lembra boost::any, esperaria
então algo que aceitasse qualquer tipo pointer-like e fizesse
type-erasure dessa forma. Pra mim any_ptr se parece mais
com um boost::variant com um operator-> que faz visitação
de operator->.

Anyway, para a tarefa dada, eu acho uma gambiarra sim, e
acho o uso de shared_ptr unicamente sim bem melhor.

Porém, me parece que o Gianni ainda não se decidiu se
há passagem de ownership do recurso ou não pela função,
o que torna o uso de qualquer unique_ptr ou shared_ptr
estranhos. Já que os mesmos implicam exatamente isso.

Se não houver transferência de ownership, uma simples
referência e raw-pointer são bem mais indicados, pois
implicam apenas "conhecimento", e não embutem
no tipo o ownership do pointed object.

> --

[]'s

Gianni Rossi

unread,
Dec 17, 2010, 7:16:14 AM12/17/10
to ccppb...@googlegroups.com
Então; o any_ptr que eu fiz foi só uma demonstração do que eu queria ter. Como eu mesmo disse, era uma gambiarra feia. No meu código eu estou usando só shared_ptr por hora, e o que me incomoda é toda vez que tenho um unique_ptr tenho que converter para shared e que perco as vantagens do unique (ser mais rápido e gastar menos recursos).

A função que recebe o objeto não se preocupa se o objeto é shared ou unique, por ela tanto faz. Por isso eu queria saber se existia um place-holder para qualquer tipo de smart_ptr, ou alguma maneira de passar qualquer smart_ptr de forma padrão. Pelo que o Lamarão falou, o shared_ptr que está no último draft tem um construtor que recebe unique_ptr. Isso resolve parte do que queria, eu ainda vou ter o maior custo do shared_ptr quando não precisar, mas pelo menos não é gambiarra.


Vou continuar pesquisando uma outra forma de fazer isso. Se eu achar uma solução como o any_ptr que fiz que não seja tão feia, eu uso. Se não, só continuo convertendo shared em unique.

Thiago Adams

unread,
Dec 17, 2010, 7:37:21 AM12/17/10
to ccppbrasil

>Pelo que o Lamarão falou, o shared_ptr que está no último draft tem um construtor >que recebe unique_ptr.  Isso resolve parte do que queria, eu ainda vou ter o maior >custo do shared_ptr quando não precisar, mas pelo menos não é gambiarra.

Mesmo sem aquele ctor && você poderia ter o mesmo efeito.
Basta liberar o ponteiro do unique_ptr e passar para o shared_ptr.

Em ambos os casos quando o shared_ptr é criado a partir de um auto_ptr/
unique_ptr ele precisa alocar um contador.

A alocação do contador do shared_ptr é uma das piores coisas em termos
de performance, comparado com soluções intrusivas (contador dentro do
objeto).

Para isso agora tem a função make_shared() que consegue alocar o
objeto e o contador de uma vez só, mas que não resolveria o caso da
passagem do unique_ptr pois o objeto do unique_ptr foi criado de outra
forma.

Eu acho que a melhor solucao para seu problema é separar a tarefa em 2
tipos , um com unique_ptr e outro com shared_ptr.
Se precisa tratar ambos de forma polimorfica, basta ter uma base em
comum. (talvez ja tenha ate no seu caso)

-x-
http://www.twitter.com/thradams




Felipe Magno de Almeida

unread,
Dec 17, 2010, 8:15:53 AM12/17/10
to ccppb...@googlegroups.com
2010/12/17 Gianni Rossi <nasus....@gmail.com>:

> Então; o any_ptr que eu fiz foi só uma demonstração do que eu queria ter.  Como eu mesmo disse, era uma gambiarra feia.  No meu código eu estou usando só shared_ptr por hora, e o que me incomoda é toda vez que tenho um unique_ptr tenho que converter para shared e que perco as vantagens do unique (ser mais rápido e gastar menos recursos).
>
> A função que recebe o objeto não se preocupa se o objeto é shared ou unique, por ela tanto faz.  Por isso eu queria saber se existia um place-holder para qualquer tipo de smart_ptr, ou alguma maneira de passar qualquer smart_ptr de forma padrão.  Pelo que o Lamarão falou, o shared_ptr que está no último draft tem um construtor que recebe unique_ptr.  Isso resolve parte do que queria, eu ainda vou ter o maior custo do shared_ptr quando não precisar, mas pelo menos não é gambiarra.
>
> Vou continuar pesquisando uma outra forma de fazer isso.  Se eu achar uma solução como o any_ptr que fiz que não seja tão feia, eu uso.  Se não, só continuo convertendo shared em unique.

O problema é que o any_ptr também vai ter overhead, e chutaria que
provavelmente maior que shared_ptr (apesar de que só medindo pra
saber).

Felipe Magno de Almeida

unread,
Dec 17, 2010, 8:18:20 AM12/17/10
to ccppb...@googlegroups.com
2010/12/17 Thiago Adams <thiago...@gmail.com>:
>

[snip]

> Eu acho que a melhor solucao para seu problema é separar a tarefa em 2


> tipos , um com unique_ptr e outro com shared_ptr.
> Se precisa tratar ambos de forma polimorfica, basta ter uma base em
> comum. (talvez ja tenha ate no seu caso)

Polimorfismo vai gerar overhead. Ownership único é apenas uma forma
especial de ownership compartilhado onde se compartilha com apenas um.

Acho que está-se procurando solução pra algo que está solucionado. E
essa solução que se irá encontrar será igual ou pior do que já se tem.

> -x-
> http://www.twitter.com/thradams

Gianni Rossi

unread,
Dec 17, 2010, 8:25:31 AM12/17/10
to ccppb...@googlegroups.com
On Friday, December 17, 2010 11:15:53 Felipe Magno de Almeida wrote:
> O problema é que o any_ptr também vai ter overhead, e chutaria que
> provavelmente maior que shared_ptr (apesar de que só medindo pra
> saber).

Bom, é um pouco mais complicado que isso. 1o. eu teriar que terminar a implementação com todos os recursos necessários (move/copy-ctors, operator=, etc.)

Supondo uma implementação 'perfeita', eu acho que teria um custo maior que o unique_ptr mas menor que o shared_ptr quando o any_ptr tiver um unique, e um custo maior que os dois quando o any_ptr tiver um shared. O custo porém pode ser pequeno; e aí é que precisaria medir isso para saber o custo vs. benefício. *Acho* que ao final, pode valer a pena, no meu caso, que simplesmente converter tudo para shared_ptr, só pelo fato de em uns 10%-30% das vezes (cute de quanto vou ter unique) eu não precise do thread-safety que o shared tem.

Thiago Adams

unread,
Dec 17, 2010, 8:26:45 AM12/17/10
to ccppbrasil
> > Eu acho que a melhor solucao para seu problema é separar a tarefa em 2
> > tipos , um com unique_ptr e outro com shared_ptr.
> > Se precisa tratar ambos de forma polimorfica, basta ter uma base em
> > comum. (talvez ja tenha ate no seu caso)
>
> Polimorfismo vai gerar overhead. Ownership único é apenas uma forma
> especial de ownership compartilhado onde se compartilha com apenas um.

É que se ele já tem o polimorfismo (acho que tem) não traria um
overhead novo.
E no caso "não shared" evitaria o overhead da passagem de unique_ptr
para shared_ptr (new do contador) e também economizaria 1 contador
para cada tarefa deste tipo.

Felipe Magno de Almeida

unread,
Dec 17, 2010, 8:34:26 AM12/17/10
to ccppb...@googlegroups.com
2010/12/17 Gianni Rossi <nasus....@gmail.com>:

Estamos apenas na terra da especulação aqui. Mas você tem que ver que
cada chamada de operator->, copy-constructor etc será do tipo:

if(is_unique)
return unique.operator->();
else
return shared.operator->();

Ou então através de polimorfismo que possivelmente geraria
cache-misses na vtable.

O que é significativamente maior em footprint e branches. A não ser
que você espere utilizar uma plataforma bizarra de SMP que exija
sincronização entre mais de um barramento, talvez overall você tenha
uma performance melhor com shared_ptr.

De qualquer forma, só faria sentido depois de benchmarked e provado
que esse é um gargalo na minha opinião. Adicionar um any_pointer
vai adicionar uma abstração nova desnecessária, que não lhe entrega
nada que um shared_ptr não entrega também e sem saber se isso fará
diferença nenhuma na performance.

Se você tivesse argumentos de segurança, como unique_ptrs sendo
compartilhados sem querer, eu estaria mais inclinado a concordar.
Mas na verdade é o contrário, já que você precisa tratar um
any_pointer como um unique_ptr por causa dele, mas também
pode usar um shared_ptr. Assim bugs podem ser encobertos ao se
testar com shared_ptr.

> --

[]'s

Reply all
Reply to author
Forward
0 new messages